diff --git a/documents/업무/5월/4째주/0526.txt b/documents/업무/5월/4째주/0526.txt new file mode 100644 index 0000000..ab7ef53 --- /dev/null +++ b/documents/업무/5월/4째주/0526.txt @@ -0,0 +1,323 @@ +const rect = target.getBoundingClientRect(); + + const clickEventY = this.groupMenuEvent.clientY; + const tartgetY = Math.floor((clickEventY - 150) * 0.1) * 10; + + const dialogRef = this.dialog.open(EditInlineInputDialogComponent, { + width: rect.width, + height: rect.height, + panelClass: 'ucap-edit-group-name-dialog', + data: { + curValue: group.name, + placeholder: '그룹명을 입력하세요.', + left: rect.left, + top: clickEventY - 100 + rect.height + } + }); + +"TypeError: Cannot read property 'height' of undefined +at ExpansionComponent.onSelectGroupMenu (http://localhost:4200/pages-group-group-page-module.980e746b5ae98aad2c91.hot-update.js:985:47) +at ExpansionComponent_ng_template_11_button_6_Template_button_click_0_listener (http://localhost:4200/pages-group-group-page-module.980e746b5ae98aad2c91.hot-update.js:581:416) +at executeListenerWithErrorHandling (http://localhost:4200/vendor.js:53654:16) +at wrapListenerIn_markDirtyAndPreventDefault (http://localhost:4200/vendor.js:53703:22) +at HTMLButtonElement. (http://localhost:4200/vendor.js:123295:38) +at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:443:35) +at Object.onInvokeTask (http://localhost:4200/vendor.js:70743:33) +at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:442:40) +at Zone.runTask (http://localhost:4200/polyfills.js:211:51) +at ZoneTask.invokeTask [as invoke] (http://localhost:4200/polyfills.js:524:38)" + + +switch (menuType) { + case 'VIEW_PROFILE': + this.onClickUser(event, userInfo as UserInfo); + break; + case 'REGISTER_FAVORITE': + this.store.dispatch( + BuddyActions.update({ + req: { + seq: Number(userInfo.seq), + isFavorit: !userInfo.isFavorit + } + }) + ); + break; + case 'NICKNAME': + { + this.editNickname(event, userInfo, rect); + } + break; + case 'COPY_BUDDY': + this.eidtUserDialog('COPY_BUDDY', group, userInfo); + break; + case 'MOVE_BUDDY': + this.eidtUserDialog('MOVE_BUDDY', group, userInfo); + break; + case 'REMOVE_BUDDY': + { + this.removeBuddy(userInfo, group); + } + break; +} + + + +private eidtUserDialog( + type: string, + group: GroupDetailData, + userInfo: UserInfoTypes + ) { + let title = ''; + let dialogType: GroupUserDialaogType; + if (type === 'COPY_BUDDY') { + title = '멤버 복사'; + dialogType = GroupUserDialaogType.Copy; + } else { + title = '멤버 이동'; + dialogType = GroupUserDialaogType.Move; + } + const dialogRef = this.dialog.open< + EditUserDialogComponent, + EditUserDialogData, + EditUserDialogResult + >(EditUserDialogComponent, { + width: '100%', + height: '100%', + data: { + title, + type: dialogType, + group, + userInfo + } + }); + dialogRef + .afterClosed() + .pipe( + take(1), + map((result: EditUserDialogResult) => { + let targetGroup: GroupDetailData; + let targetUserSeqs: string[]; + if (result.type === GroupUserDialaogType.Add) { + targetGroup = result.group; + targetUserSeqs = []; + result.selelctUserList.forEach((u) => { + targetUserSeqs.push(u.seq + ''); + }); + this.store.dispatch( + GroupActions.updateMember({ targetGroup, targetUserSeqs }) + ); + } else if (result.type === GroupUserDialaogType.Copy) { + if (!!result.selectGroupList && result.selectGroupList.length > 0) { + result.selectGroupList.forEach((g) => { + targetGroup = g; + targetUserSeqs = []; + g.userSeqs.map((seq) => { + targetUserSeqs.push(seq); + }); + if (targetUserSeqs.length === 0) { + result.selelctUserList.forEach((user) => { + targetUserSeqs.push(user.seq as any); + }); + } else { + result.selelctUserList.forEach((user) => { + const find = targetUserSeqs.indexOf(user.seq as any); + if (find < 0) { + targetUserSeqs.push(user.seq as any); + } + }); + } + this.store.dispatch( + GroupActions.updateMember({ targetGroup, targetUserSeqs }) + ); + }); + } + } else if (result.type === GroupUserDialaogType.Move) { + const fromGroup = result.group; + let toGroup: GroupDetailData; + targetUserSeqs = []; + if (!!result.selectGroupList && result.selectGroupList.length > 0) { + result.selectGroupList.forEach((g) => { + toGroup = g; + targetUserSeqs = []; + result.selelctUserList.forEach((user) => { + targetUserSeqs.push(user.seq as any); + }); + this.store.dispatch( + GroupActions.moveMember({ + fromGroup, + toGroup, + targetUserSeq: targetUserSeqs + }) + ); + }); + } + } else if (result.type === GroupUserDialaogType.Create) { + targetUserSeqs = []; + result.selelctUserList.forEach((u) => { + targetUserSeqs.push(u.seq + ''); + }); + this.store.dispatch( + GroupActions.create({ + groupName: result.groupName, + targetUserSeqs + }) + ); + } + }), + catchError((err) => { + return of(err); + }) + ) + .subscribe(); + } + + private removeBuddy(userInfo: UserInfoF, group: GroupDetailData) { + const dialogRef = this.dialog.open< + ConfirmDialogComponent, + ConfirmDialogData, + ConfirmDialogResult + >(ConfirmDialogComponent, { + data: { + title: '', + html: this.i18nService.t('label.confirmRemoveBuddy') + } + }); + dialogRef + .afterClosed() + .pipe( + take(1), + map((result) => { + if (!!result && result.choice) { + const trgtUserSeq = group.userSeqs.filter( + (user) => user + '' !== userInfo.seq + '' + ); + + this.store.dispatch( + GroupActions.updateMember({ + targetGroup: group, + targetUserSeqs: trgtUserSeq + }) + ); + } + }), + catchError((err) => { + return of(err); + }) + ) + .subscribe(); + } + private editNickname(event: MouseEvent, userInfo: UserInfoF, rect: any) { + const clickEventY = event.clientY; + + // const dialogRef = this.dialog.open(EditInlineInputDialogComponent, { + // width: rect.width - 30 + '', + // height: rect.height, + // panelClass: 'ucap-edit-group-name-dialog', + // data: { + // curValue: userInfo.nickName, + // placeholder: '닉네임을 설정하세요.', + // left: rect.left + 70, + // top: rect.top + // } + // }); + + // dialogRef + // .afterClosed() + // .pipe( + // take(1), + // map((result) => { + // if ( + // !!result && + // result.choice && + // result.curValue.localeCompare(userInfo.nickName) !== 0 + // ) { + // this.store.dispatch( + // BuddyActions.nickname({ + // req: { + // userSeq: Number(userInfo.seq), + // nickname: result.curValue + // } + // }) + // ); + // } + // }), + // catchError((err) => { + // return of(err); + // }) + // ) + // .subscribe(); + } + +리팩토링 + 셀렉트 이용 + 이벤트가 다른 컴포넌트 시리즈 분리 + +컴포넌트 후보 + 사용자 선택 (chips) + 검색 결과 + 프로필 리스트 + +그룹 다이얼로그 + 생성, + 출력 + 그룹명, 그룹 유저 리스트, 조직도, 검색, 검색 결과 + 기능 + 그룹명 유효성 검사 + 그룹 유저 리스트 + 사용자 체크에 대한 처리, 그룹 체크에 대한 처리, 체크박스 + 한줄 수정, + 출력 + 한줄 입력창, 적용 버튼, 취소 버튼 + 기능 + 한줄 입력에 대한 유효성 검사 + 절대 위치에 출력할 수 있게 포지션 계산 + 유저 변경(이동, 복사, 생성, 삭제), + + 유저 변경(이동, 복사) +그룹 메뉴 + 출력 + 메뉴 + 이름 바꾸기 + 그룹 삭제 + 기능 + 그룹 대화, 쪽지 => 이벤트 호출 + 그룹 이름 => position 계산, 적용, 취소에 대한 처리, 액션 처리 + 그룹 삭제 => 사용자 확인 다이얼로그 출력 및 액션에 대한 처리 + +익스팬션 + 프로필 리스트 아이템 + 출력 + 프로필 메뉴, 프레젠스, 프로핊 이미지, 이름, 직함, 부서, 인트로, 닉네임 + 기능 + 프로필 보기 + 즐겨 찾기 설정 + 닉네임 설정 + 대화 상대 복사, 이동 + 삭제 + 마우스오버&리브 이벤트에 대한 버튼 출력 + 모어 메뉴 출력 포지션 계산 + +검색 + 출력 + 입력창, 검색 버튼, 입력 삭제 버튼, 회사 리스트 + 기능 + 입력 이벤트 + 검색 액션 처리 + 삭제 버튼 액션 처리 + 회사 리스트 조회 +셀렉트 그룹 + 검색 + 그룹명 입력 + 기존 그룹 리스트 + 체크박스 +셀렉트 유저 + 익스팬션 + 프로필 리스트 아이템 + 프레젠스, 프로필 이미지, 이름, 부서, 직함, 체크박스 + + +그룹용 프로필 리스트 아이템 + 마우스오버 -> 버튼 컴포넌트 + +다이얼로그 프로필 리스트 아이템 + 체크박스 diff --git a/documents/업무/5월/4째주/0527.txt b/documents/업무/5월/4째주/0527.txt new file mode 100644 index 0000000..50cb070 --- /dev/null +++ b/documents/업무/5월/4째주/0527.txt @@ -0,0 +1,58 @@ +todo + 다국어 적용 + + 프로필 컴포넌트 정리 + org 프로필 컴포넌트 적용 + 마우스오버 이벤트 + 히든 버튼 적용 + 체크박스 이벤트 + 익스팬션 컴포넌트 정리 + 그룹 메뉴 + 그룹별 메뉴 히든 처리 + 프로필 메뉴 + 프로필 메뉴 히든 처리 + 온/오프 리스트 + 접속동료 리스트 + + 다이얼로그 컴포넌트 정리 + 관리 + 삭제, 추가, 이동, 복사, 검색 + 그룹이름 유효성 검사 + 선택 컴포넌트 적용 + 생성 + 그룹이름 유효성 검사 + 선택 컴포넌트 적용 + 한줄 편집 + + 수정 + + 셀렉트 유저 컴포넌트 + 셀렉트 컴포넌트 적용 + 셀렉트 그룹 컴포넌트 + +검색 결과 컴포넌트 + +그룹명 컴포넌트 + + + + +// if (params.isChecked) { +// params.groupBuddyList.buddyList.forEach((item) => { +// if ( +// this.selectedUserList.filter((user) => user.seq === item.seq) +// .length === 0 +// ) { +// this.selectedUserList = [...this.selectedUserList, item]; +// } +// }); +// } else { +// this.selectedUserList = this.selectedUserList.filter( +// (item) => +// params.groupBuddyList.buddyList.filter((del) => del.seq === item.seq) +// .length === 0 +// ); +// } + +// this.changeDetectorRef.markForCheck(); +// this.changeUserList.emit(this.selectedUserList); \ No newline at end of file diff --git a/documents/업무/5월/4째주/backup/profile-list-item-02.component.html b/documents/업무/5월/4째주/backup/profile-list-item-02.component.html new file mode 100644 index 0000000..423b2a6 --- /dev/null +++ b/documents/업무/5월/4째주/backup/profile-list-item-02.component.html @@ -0,0 +1,85 @@ +
+ + +
+ +
+
+ + + + + + + + + diff --git a/documents/업무/5월/4째주/backup/profile-list-item.component.html b/documents/업무/5월/4째주/backup/profile-list-item.component.html new file mode 100644 index 0000000..539f68e --- /dev/null +++ b/documents/업무/5월/4째주/backup/profile-list-item.component.html @@ -0,0 +1,101 @@ +
+ +
+ {{ userInfo.intro }} +
+
+ {{ userInfo.nickName }} +
+ +
+ + + + +
+
+ +
+
diff --git a/documents/업무/5월/4째주/backup/profile-list-item.component.scss b/documents/업무/5월/4째주/backup/profile-list-item.component.scss new file mode 100644 index 0000000..1111e59 --- /dev/null +++ b/documents/업무/5월/4째주/backup/profile-list-item.component.scss @@ -0,0 +1,136 @@ +@import '~@ucap/lg-scss/mixins'; + +.user-list { + display: flex; + flex-flow: row nowrap; + justify-content: space-between; + padding: 0 16px; + height: 70px; + align-items: center; + &.line-top { + border-top: 1px solid $gray-rec; + } + .user-profile-info { + display: inline-flex; + flex-direction: row; + flex-grow: 2.3; + .user-profile-thumb { + @include profile-avatar-default( + 0 5px 5px 0, + 8, + $green, + 18px + ); //오른 아래 공간, 모바일 온라인 아이콘 크기, 모바일 아이콘 색, 모바일 아이콘 bg크기 + .presence { + //PC 상태 + @include presence-state(8px); //원크기 + } + .profile-image { + @include avatar-img(36px, 2px); //아바타 크기, 왼쪽공간 + } + } + .user-info { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + padding-left: 16px; + .user-n-g { + display: flex; + flex-flow: row-reverse nowrap; + align-items: flex-end; + height: 22px; + .user-name { + @include ellipsis-column(1); + height: 22px; + font: { + size: 16px; + weight: 600; + } + color: $gray-re21; + order: 1; + -ms-flex-order: 1; + } + .user-grade { + @include ellipsis(1); + align-self: stretch; + font: { + size: 13px; + } + color: $gray-re70; + margin-left: 4px; + order: 0; + -ms-flex-order: 0; + } + } + .dept-name { + @include ellipsis(1); + font-size: 12px; + color: $gray-re6; + line-height: 16px; + } + } + } + .intro { + display: inline-flex; + flex-flow: row nowrap; + flex-basis: 35%; + flex-grow: 0; + align-items: baseline; + p { + font-size: 11px; + line-height: 1.4; + @include ellipsis(2); + height: 30px; + } + &:before { + content: 'chat'; + @include font-family-ico($font-ico-default, 12, center, $lipstick); + flex-direction: row; + align-items: flex-start; + width: 12px; + height: 12px; + line-height: 12px; + margin-right: 4.8px; + position: relative; + top: 2px; + } + } + .btn-partner-set { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 25px; + border-top: 1px solid rgba(255, 255, 255, 0.8); + border-bottom: 1px solid rgba(255, 255, 255, 0.8); + height: 20px; + margin-top: 20px; + img { + vertical-align: top; + } + } + .intro-name { + display: inline-flex; + flex-flow: row nowrap; + flex-basis: 35%; + align-items: center; + justify-content: center; + overflow: hidden; + span { + display: inline-block; + text-align: center; + width: 100%; + height: 20px; + line-height: 20px; + color: $gray-re70; + font-size: 11px; + padding: 0 10px; + border-radius: 30px; + border: solid 1px $warm-pink; + background-color: #ffffff; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } +} diff --git a/documents/업무/5월/4째주/backup/profile-list-item.component.spec.ts b/documents/업무/5월/4째주/backup/profile-list-item.component.spec.ts new file mode 100644 index 0000000..9965458 --- /dev/null +++ b/documents/업무/5월/4째주/backup/profile-list-item.component.spec.ts @@ -0,0 +1,26 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { ProfileListItemComponent } from './profile-list-item.component'; + +describe('ucap::ucap::organization::ProfileListItemComponent', () => { + let component: ProfileListItemComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ProfileListItemComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ProfileListItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/documents/업무/5월/4째주/backup/profile-list-item.component.ts b/documents/업무/5월/4째주/backup/profile-list-item.component.ts new file mode 100644 index 0000000..49027ec --- /dev/null +++ b/documents/업무/5월/4째주/backup/profile-list-item.component.ts @@ -0,0 +1,214 @@ +import { + Component, + OnInit, + OnDestroy, + ChangeDetectionStrategy, + ChangeDetectorRef, + Input, + EventEmitter, + Output, + ElementRef, + Self +} from '@angular/core'; +import { UserInfo, GroupDetailData } from '@ucap/protocol-sync'; +import { UserInfoSS, UserInfoF, UserInfoDN } from '@ucap/protocol-query'; +import { UserInfo as RoomUserInfo } from '@ucap/protocol-room'; +import { StatusBulkInfo, StatusInfo } from '@ucap/protocol-status'; +import { PresenceType, StatusCode } from '@ucap/core'; +import { I18nService } from '@ucap/ng-i18n'; +import { ucapAnimations } from '@ucap/ng-ui'; + +export type UserInfoTypes = + | UserInfo + | UserInfoSS + | UserInfoF + | UserInfoDN + | RoomUserInfo; + +@Component({ + selector: 'app-group-profile-list-item', + templateUrl: './profile-list-item.component.html', + styleUrls: ['./profile-list-item.component.scss'], + animations: ucapAnimations, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ProfileListItemComponent implements OnInit, OnDestroy { + @Input() + userInfo: UserInfoF; + + @Input() + group: GroupDetailData; + + @Input() + isSearchData = false; + + @Input() + defaultProfileImage: string; + + @Input() + profileImageRoot: string; + + @Input() + set presence(info: StatusBulkInfo | StatusInfo) { + this._presence = info; + } + get presence(): StatusBulkInfo | StatusInfo { + return this._presence; + } + _presence: StatusBulkInfo | StatusInfo; + + @Input() + showMenu = true; + + @Input() + checkable = false; + @Input() + set isChecked(checked: boolean) { + this._isChecked = checked; + } + + get isChecked(): boolean { + return this._isChecked; + } + _isChecked = false; + + @Output() + checked = new EventEmitter<{ + isChecked: boolean; + userInfo: UserInfoTypes; + }>(); + + @Output() + moreMenu: EventEmitter<{ + event: MouseEvent; + userInfo: UserInfoTypes; + group: GroupDetailData; + rect: any; + }> = new EventEmitter(); + + isClicked = false; + isShowMenu = false; + + @Input() + isMe = false; + + PresenceType = PresenceType; + isClickMore = false; + + constructor( + private changeDetectorRef: ChangeDetectorRef, + private i18nService: I18nService, + @Self() private elementRef: ElementRef + ) { + this.i18nService.setDefaultNamespace('organization'); + } + + ngOnInit(): void {} + + ngOnDestroy(): void {} + + onClickProfileImage(event: Event, userInfo: UserInfoTypes): void {} + + onChangeCheck(value: boolean, userInfo: UserInfoTypes) { + this.checked.emit({ + isChecked: value, + userInfo + }); + } + + getPresence(type: PresenceType): string { + let status: string; + let rtnClass = ''; + switch (type) { + case PresenceType.PC: + status = !!this.presence ? this.presence.pcStatus : undefined; + break; + case PresenceType.MOBILE: + status = !!this.presence ? this.presence.mobileStatus : undefined; + break; + } + + switch (status) { + case StatusCode.OnLine: + rtnClass = 'online'; + break; + case StatusCode.Away: + rtnClass = 'absence'; + break; + case StatusCode.Busy: + rtnClass = 'other-business'; + break; + default: + rtnClass = 'offline'; + break; + } + + return rtnClass; + } + + getPresenceMsg(): string { + let presenceMsg = this.i18nService.t('presence.offline'); + + if (!!this.presence) { + switch (this.presence.pcStatus) { + case StatusCode.OnLine: + presenceMsg = this.i18nService.t('presence.online'); + break; + case StatusCode.Away: + presenceMsg = this.i18nService.t('presence.away'); + break; + case StatusCode.Busy: + if ( + !!this.presence.statusMessage && + this.presence.statusMessage !== '.' + ) { + presenceMsg = this.presence.statusMessage; + } else { + presenceMsg = this.i18nService.t('presence.statusMessage1'); + } + break; + } + } + + return presenceMsg; + } + + onClickMore(event: MouseEvent) { + this.isClickMore = true; + const rect = this.elementRef.nativeElement.getBoundingClientRect(); + + this.moreMenu.emit({ + event, + userInfo: this.userInfo, + group: this.group, + rect + }); + } + + onClickProfileContextMenu(event: MouseEvent, type: string) {} + onClickProfile(event: MouseEvent) { + event.preventDefault(); + event.stopPropagation(); + if (this.showMenu && !this.isMe) { + this.isShowMenu = true; + } + } + onMouseover(event: MouseEvent): void { + if (this.showMenu && !this.isMe) { + this.isShowMenu = true; + if (this.isClickMore) { + this.isClickMore = false; + } + } + event.preventDefault(); + event.stopPropagation(); + } + onMouseleave(event: MouseEvent): void { + if (this.showMenu && !this.isMe) { + this.isShowMenu = false; + } + + event.preventDefault(); + event.stopPropagation(); + } +} diff --git a/documents/업무/5월/4째주/backup/temp.txt b/documents/업무/5월/4째주/backup/temp.txt new file mode 100644 index 0000000..25baf1c --- /dev/null +++ b/documents/업무/5월/4째주/backup/temp.txt @@ -0,0 +1,128 @@ + +
+ +
+ + +
+ + + + {{ userInfo.name }} + clear + + +
+ + + + {{ selectedUserList.length }} / 300 + + + + + + + + + + {{ selectedUserList.length }} + + + +
+ + + + + + +
+ + + + {{ userInfo.name }} + clear + + +
+ + + + {{ selectedUserList.length }} / 300 + + + + + + + + + + {{ selectedUserList.length }} + + + +
+ + +manage.dialog.component 버그 (동료 리스트와 선택유저 리스트 동기화) + \ No newline at end of file diff --git a/documents/업무/5월/4째주/backup/ucap-0527.zip b/documents/업무/5월/4째주/backup/ucap-0527.zip new file mode 100644 index 0000000..ad24931 Binary files /dev/null and b/documents/업무/5월/4째주/backup/ucap-0527.zip differ diff --git a/documents/업무/5월/4째주/backup/ucap-angular-0527.zip b/documents/업무/5월/4째주/backup/ucap-angular-0527.zip new file mode 100644 index 0000000..6ab4efb Binary files /dev/null and b/documents/업무/5월/4째주/backup/ucap-angular-0527.zip differ diff --git a/documents/업무/5월/4째주/backup/ucap-lg-web-0527.zip b/documents/업무/5월/4째주/backup/ucap-lg-web-0527.zip new file mode 100644 index 0000000..8731dd6 Binary files /dev/null and b/documents/업무/5월/4째주/backup/ucap-lg-web-0527.zip differ diff --git a/documents/업무/new-pc-doc/New PC 메신저 릴리즈 Plan_박병은_0526.xls b/documents/업무/new-pc-doc/New PC 메신저 릴리즈 Plan_박병은_0526.xls new file mode 100644 index 0000000..d947020 Binary files /dev/null and b/documents/업무/new-pc-doc/New PC 메신저 릴리즈 Plan_박병은_0526.xls differ