diff --git a/documents/업무/6월/3째주/0618.txt b/documents/업무/6월/3째주/0618.txt new file mode 100644 index 0000000..488760b --- /dev/null +++ b/documents/업무/6월/3째주/0618.txt @@ -0,0 +1,94 @@ +그룹 디버그 + 새그룹 추가 + 그룹명 지정하지 않았는데 "그룹지정 후 완료" 버튼으로 진행됨. + " " 블랭크 입력 후 "완료" 시 빈명칭의 그룹이 생성됨. (O) + ime 처리 X + 전체 체크박스에 체크 안됨. + 전체 체크박스에 체크해제 안됨. + 기존 그룹 동료를 검색하면 체크가 되어 있지 않음(seq가 다른 타입) + + 그룹이름 바꾸기 + max length 체크 안되며, 매우 길 경우 바뀌지 않음. + + 그룹멤버관리 + +프로필 수정 사항 + 프로필 이미지 출력 X + 닉네임 길이 체크 + 닉네임 라벨이 없어지지 않음 + 기존 닉네임값 출력 되지 않음 + +"http://13.124.88.127:8011/ProfileImage" +/2019/12/16/PF_9824_84924202.jpg +문의 + 닉네임 입력 길이 문의 + +mat-form-field +form-field-input-searchword +ng-tns-c159-5 +mat-primary +mat-form-field-type-mat-input +mat-form-field-can-float +mat-form-field-has-label +mat-form-field-should-float + +mat-form-field +ng-tns-c159-7 +mat-primary +mat-form-field-type-mat-input +mat-form-field-can-float +mat-form-field-should-float +mat-form-field-has-label + + + +1 CL → SS SSVC_TYPE_QUERY_USER_SEQ_REQ 21 사용자 SEQ 검색 DivCD(s) 로그인IDs(s) 기관코드(s) 상세정보여부(s) 발신자회사코드(s) 발신자임직원유형(s) +2 SS → CL SSVC_TYPE_QUERY_USER_SEQ_DATA 22 사용자 SEQ 정보 (상세여부 E) DivCD(s) {사용자정보-F}1 {사용자정보-F}2 {사용자정보-F}n … + 22 사용자 SEQ 정보 (상세여부 N) DivCD(s) {SEQ정보}1 {SEQ정보}2 {SEQ정보}n +2 SS → CL SSVC_TYPE_QUERY_USER_SEQ_DATA2 24 사용자 SEQ 정보 (상세여부 Y) DivCD(s) {사용자정보-SS}1 {사용자정보-SS}2 {사용자정보-SS}n … +3 SS → CL SSVC_TYPE_QUERY_USER_SEQ_RES 23 DivCD(s) + + + +"66264고재범 (책임) GUC00601064210909 jbgoh@cnspartner.comN석유화학정보화팀YKY999A41454   CJaebeom Goh (Manager) Petrochemical Information Team 155YNP" +닉네임 +상태메세지 +대화 검색 + +userInfoF 프로토콜 생성 요청 + +ERROR TypeError: Cannot read property 'seq' of undefined +at profile-01.component.ts:156 +at Array.filter () +at SafeSubscriber._next (profile-01.component.ts:155) +at SafeSubscriber.__tryOrUnsub (Subscriber.js:183) +at SafeSubscriber.next (Subscriber.js:122) +at Subscriber._next (Subscriber.js:72) +at Subscriber.next (Subscriber.js:49) +at DistinctUntilChangedSubscriber._next (distinctUntilChanged.js:50) +at DistinctUntilChangedSubscriber.next (Subscriber.js:49) + + +// switch (type) { +// case 'CHAT': +// this.appChatService.newOpenRoom( +// [this.userInfo.seq as any], +// false, +// this.loginRes +// ); +// break; +// case 'MESSAGE': +// break; +// case 'MOBILE': +// break; +// case 'OFFICE': +// break; +// case 'VIDEO_CONFERENCE': +// break; +// } + +assets/images/ico/img_nophoto. + +http://13.124.88.127:8011/Prof + +/2019/12/16/PF_9824_84924202.j \ No newline at end of file diff --git a/documents/업무/6월/3째주/0619.txt b/documents/업무/6월/3째주/0619.txt new file mode 100644 index 0000000..675a989 --- /dev/null +++ b/documents/업무/6월/3째주/0619.txt @@ -0,0 +1,44 @@ +작업 + 그룹 + 관리 다이얼로그 컴포넌트 + 타이틀 변경 + 컨텍스트 변경에 대한 액션 변경 + 그룹 선택, 동료 선택 체크 처리 + + 동료 삭제 + 동료 추가 + 현재 그룹 seq + 기존 userseqs + 변경된 userseqs + + 동료 이동 + 동료 복사 + 그룹 생성 + + 변수 + 타이틀 + 현재 인덱스 + 그룹 이름 + 현재 선택된 유저 리스트 + 현재 선택된 그룹 + + 그룹 셀렉트 컴포넌트 + 그룹 체크 박스 (전체, 해제) + 유저 셀렉트 컴포넌트 + + 프로필 + + list -> scroll checkbox label + + +전체 체크박스 + 아이템 한개 언체크 시 전체 체크박스 해제 + + + + \ No newline at end of file diff --git a/documents/업무/6월/3째주/0620.txt b/documents/업무/6월/3째주/0620.txt new file mode 100644 index 0000000..3fff8bd --- /dev/null +++ b/documents/업무/6월/3째주/0620.txt @@ -0,0 +1,67 @@ +angular 수정 + 프로필 메뉴 클릭 시 사용자 바뀜 + +그룹 멤버 관리 + 그룹 복사, 그룹이동 시 선택된 유저가 없는 경우 + 버튼 비활성화 + 그룹 정렬 방식이 그룹 메뉴의 리스트와 다름 + 새그룹 추가시 validation 여부와 상관없이 확인 버튼 동작함 + 조회시 검색결과 카운트 표출안됨 + 조회시 검색결과 리스트 스크롤 오류 + 기존그룹 없을 시 출력될 화면 + + + + + +if ( + !!datas && + !!this.searchUserInfos && + datas.length === this.searchUserInfos.length + ) { + this.checkboxAllSearch.checked = datas[0].checked; + } else { + // if (!!this.searchUserInfos && this.searchUserInfos.length > 0) { + // const tempUserInfos: UserInfoSS[] = []; + + // this.searchUserInfos.map((user) => { + // this.selectedUserList.every((selectUser) => { + // if (user.seq === selectUser.seq) { + // tempUserInfos.push(user); + // return false; + // } + // return true; + // }); + // }); + + // if ( + // tempUserInfos.length === this.searchUserInfos.length && + // !!this.checkboxAllSearch && + // !this.checkboxAllSearch.checked + // ) { + // this.checkboxAllSearch.checked = true; + // } else { + // this.checkboxAllSearch.checked = false; + // } + // } + + this.selectedUserList. + } + +그룹이동 + 그룹하나 선택 + 그룹 다중 선택 + 사용자 한명 + 사용자 다중 선택 + + 기존 그룹에서 사용자 삭제 + 이동시킬 그룹으로 업데이트 + \ No newline at end of file diff --git a/documents/업무/6월/3째주/backup/manage.dialog.component.html b/documents/업무/6월/3째주/backup/manage.dialog.component.html new file mode 100644 index 0000000..e8c0fb9 --- /dev/null +++ b/documents/업무/6월/3째주/backup/manage.dialog.component.html @@ -0,0 +1,108 @@ +
+ +
+ {{ data.title }} +
+
+ + +
+
+ {{ + data.groupBuddyList.group.name + }} + +
+ +
+ + + +
+
+
+ +
+ + +
+
+ + + 선택된 대화상대 ({{ + selectedUserList.length + }}) + + +
+
+
+
+ +
+
+ + + +
+
+ + +
+
+
+
diff --git a/documents/업무/6월/3째주/backup/manage.dialog.component.ts b/documents/업무/6월/3째주/backup/manage.dialog.component.ts new file mode 100644 index 0000000..de72d27 --- /dev/null +++ b/documents/업무/6월/3째주/backup/manage.dialog.component.ts @@ -0,0 +1,394 @@ +import { Subject, of } from 'rxjs'; + +import { + Component, + OnInit, + OnDestroy, + ChangeDetectionStrategy, + ChangeDetectorRef, + Inject, + ComponentFactoryResolver, + ViewChild, + ViewContainerRef, + ComponentRef +} from '@angular/core'; + +import { Store } from '@ngrx/store'; + +import { + MatDialogRef, + MAT_DIALOG_DATA, + MatDialog +} from '@angular/material/dialog'; + +import { UserInfo, GroupDetailData } from '@ucap/protocol-sync'; +import { UserInfoSS, UserInfoF, UserInfoDN } from '@ucap/protocol-query'; +import { UserInfo as RoomUserInfo } from '@ucap/protocol-room'; +import { MatStepper } from '@angular/material/stepper'; +import { I18nService } from '@ucap/ng-i18n'; +import { GroupActions } from '@ucap/ng-store-group'; +import { + AlertDialogComponent, + AlertDialogData, + AlertDialogResult, + ConfirmDialogComponent, + ConfirmDialogResult, + ConfirmDialogData +} from '@ucap/ng-ui'; +import { SelectUserSectionComponent } from '../components/select-user.section.component'; +import { take, map, catchError } from 'rxjs/operators'; +import { SelectGroupSectionComponent } from '../components/select-group.section.component'; +import { SelectUserDialogType, GroupUserDialaogType } from '@app/types'; + +export type UserInfoTypes = + | UserInfo + | UserInfoSS + | UserInfoF + | UserInfoDN + | RoomUserInfo; + +export enum ManageContentType { + Add = 'ADD_COMPONENT', + Copy = 'COPY_COMPONENT', + Move = 'MOVE_COMPONENT', + Delete = 'DELETE_COMPONENT', + None = 'NONE_COMPONENT' +} +export interface ManageDialogData { + title: string; + groupBuddyList?: { group: GroupDetailData; buddyList: UserInfo[] }; +} +export interface ManageDialogResult { + type: GroupUserDialaogType; + groupName: string; + group?: GroupDetailData; + selelctUserList?: UserInfoTypes[]; + selectGroupList?: GroupDetailData[]; +} + +@Component({ + selector: 'app-dialog-group-manage', + templateUrl: './manage.dialog.component.html', + styleUrls: ['./manage.dialog.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ManageDialogComponent implements OnInit, OnDestroy { + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: ManageDialogData, + private changeDetectorRef: ChangeDetectorRef, + private store: Store, + private i18nService: I18nService, + public dialog: MatDialog, + private cfResolver: ComponentFactoryResolver + ) {} + + @ViewChild('dialogContainer', { static: true, read: ViewContainerRef }) + dialogContainer: ViewContainerRef; + + componentRef: ComponentRef; + private ngOnDestroySubject: Subject; + currentType: GroupUserDialaogType; + SelectUserDialogType = SelectUserDialogType; + GroupUserDialaogType = GroupUserDialaogType; + + currentStep = 0; + groupName = ''; + + ManageContentType = ManageContentType; + + selectedUserList: UserInfoTypes[]; + selectedGroupList: GroupDetailData[]; + selectContentType: ManageContentType; + + ngOnInit(): void { + this.ngOnDestroySubject = new Subject(); + + this.selectedUserList = []; + this.selectContentType = ManageContentType.None; + } + + ngOnDestroy(): void { + if (!!this.ngOnDestroySubject) { + this.ngOnDestroySubject.next(); + this.ngOnDestroySubject.complete(); + } + } + + onClosed(event: MouseEvent): void { + this.dialogRef.close(); + } + + onDelete(stepper: MatStepper) { + if ( + !!this.selectedUserList && + this.selectedUserList.length > 0 && + this.currentStep === 0 + ) { + let titleStr = ''; + this.selectedUserList.forEach((user, idx) => { + let userTitle = user.name + ' ' + user.grade; + if (idx < this.selectedUserList.length) { + userTitle = userTitle + ', '; + } + titleStr = titleStr.concat('', userTitle); + }); + const dialogRef = this.dialog.open< + ConfirmDialogComponent, + ConfirmDialogData, + ConfirmDialogResult + >(ConfirmDialogComponent, { + panelClass: 'min-create-dialog', + data: { + title: '동료 삭제', + html: titleStr + '을 삭제하시겠습니까?' + } + }); + dialogRef + .afterClosed() + .pipe( + take(1), + map((result) => { + if (!!result && result.choice) { + const trgtUserSeq: string[] = []; + + this.selectedUserList.forEach((userIfno) => { + const tempSeqs = this.data.groupBuddyList.group.userSeqs.filter( + (seq) => seq !== userIfno.seq + ); + + tempSeqs.map((seq) => trgtUserSeq.push(seq)); + }); + + console.log(trgtUserSeq); + + this.store.dispatch( + GroupActions.updateMember({ + targetGroup: this.data.groupBuddyList.group, + targetUserSeqs: trgtUserSeq + }) + ); + this.dialogRef.close(); + } + }), + catchError((err) => { + return of(err); + }) + ) + .subscribe(); + } + } + onUpdateMember(stepper: MatStepper, type: GroupUserDialaogType) { + this.dialogContainer.clear(); + this.currentType = type; + this.selectedGroupList = []; + const isMemberMove = type === GroupUserDialaogType.Copy ? false : true; + + const factory = this.cfResolver.resolveComponentFactory( + SelectGroupSectionComponent + ); + + this.componentRef = this.dialogContainer.createComponent(factory); + const cpInstance = this.componentRef.instance; + // cpInstance.title = title; + cpInstance.isMemberMove = isMemberMove; + cpInstance.isDialog = true; + cpInstance.checkable = true; + cpInstance.curGroup = this.data.groupBuddyList.group; + cpInstance.selectedGroupList = this.selectedGroupList; + cpInstance.selectedUserList = this.selectedUserList; + cpInstance.changeUserList.subscribe( + (datas: { checked: boolean; userInfo: UserInfoSS }[]) => { + this.changeSelectedUserList(datas); + cpInstance.selectedUserList = this.selectedUserList; + } + ); + cpInstance.changeGroupList.subscribe((data: { group: GroupDetailData }) => { + if ( + this.selectedGroupList.filter((g) => g.seq === data.group.seq) + .length === 0 + ) { + this.selectedGroupList = [...this.selectedGroupList, data.group]; + } else { + this.selectedGroupList = this.selectedGroupList.filter( + (g) => g.seq !== data.group.seq + ); + } + cpInstance.selectedGroupList = this.selectedGroupList; + }); + cpInstance.changeGroupName.subscribe((groupName) => { + this.groupName = groupName; + }); + this.currentStep++; + stepper.next(); + } + + onAdd(stepper: MatStepper) { + this.dialogContainer.clear(); + this.currentType = GroupUserDialaogType.Add; + + const factory = this.cfResolver.resolveComponentFactory( + SelectUserSectionComponent + ); + + this.componentRef = this.dialogContainer.createComponent(factory); + const cpInstance = this.componentRef.instance; + cpInstance.isDialog = true; + cpInstance.checkable = true; + cpInstance.selectedUserList = this.data.groupBuddyList.buddyList; + + // const cpElement: HTMLElement = this.componentRef.location.nativeElement; + // cpElement.style.height = '400px'; + + cpInstance.toggleCheckUser.subscribe( + (datas: { checked: boolean; userInfo: UserInfoSS }[]) => { + this.changeSelectedUserList(datas); + cpInstance.selectedUserList = this.selectedUserList; + } + ); + + this.currentStep++; + stepper.next(); + } + + onChangeUserList(datas: { checked: boolean; userInfo: UserInfoSS }[]) { + this.changeSelectedUserList(datas); + } + + private changeSelectedUserList( + datas: { + checked: boolean; + userInfo: UserInfoSS; + }[] + ) { + if (!datas || 0 === datas.length) { + return; + } + + const pushs: UserInfoSS[] = []; + const pops: UserInfoSS[] = []; + + datas.forEach((d) => { + const i = this.selectedUserList.findIndex( + (u) => u.seq === d.userInfo.seq + ); + if (d.checked) { + if (-1 === i) { + pushs.push(d.userInfo); + } + } else { + if (-1 < i) { + pops.push(d.userInfo); + } + } + }); + + if (0 < pushs.length) { + this.selectedUserList = [...this.selectedUserList, ...pushs]; + } + + if (0 < pops.length) { + this.selectedUserList = this.selectedUserList.filter( + (u) => -1 === pops.findIndex((p) => p.seq === u.seq) + ); + } + } + onCnacel(stepper: MatStepper) { + if (!!this.selectedUserList && this.selectedUserList.length > 0) { + this.selectedUserList = []; + } + this.currentStep--; + stepper.previous(); + } + onConfirm(stepper: MatStepper) { + switch (this.currentType) { + case GroupUserDialaogType.Add: + { + if (!!this.selectedUserList && this.selectedUserList.length > 0) { + this.doAction(); + } + } + break; + case GroupUserDialaogType.Copy: + case GroupUserDialaogType.Move: + { + if ( + !!this.selectedUserList && + this.selectedUserList.length === 0 && + this.groupName === '' + ) { + this.dialog.open< + AlertDialogComponent, + AlertDialogData, + AlertDialogResult + >(AlertDialogComponent, { + panelClass: 'min-create-dialog', + data: { + title: 'Error', + html: '선택된 유저가 없습니다.' + } + }); + + return; + } + + this.doAction(); + } + break; + } + } + + doAction() { + this.dialogContainer.clear(); + if (!!this.groupName && this.groupName.trim().localeCompare('') !== 0) { + this.currentType = GroupUserDialaogType.Create; + } else { + this.groupName = undefined; + } + + this.dialogRef.close({ + type: this.currentType, + groupName: this.groupName, + group: this.data.groupBuddyList.group, + selelctUserList: this.selectedUserList, + selectGroupList: this.selectedGroupList + }); + } + + /** 개별 체크여부 */ + getCheckedUser(userInfo: UserInfoSS) { + if (!!this.selectedUserList && this.selectedUserList.length > 0) { + return ( + this.selectedUserList.filter( + (item) => (item.seq as any) === (userInfo.seq as any) + ).length > 0 + ); + } + + return false; + } + + onToggleCheck(data: { checked: boolean; userInfo: UserInfoSS }) { + this.changeSelectedUserList([data]); + } + + onRemovedProfileSelection(userInfo: UserInfo) { + const i = this.selectedUserList.findIndex( + (u) => (u.seq as any) === (userInfo.seq as any) + ); + + if (-1 < i) { + this.selectedUserList = this.selectedUserList.filter( + (u) => (u.seq as any) !== (userInfo.seq as any) + ); + } + } + + removableForSelection = (userInfo: UserInfo) => { + return true; + }; + + colorForSelection = (userInfo: UserInfo) => { + return 'accent'; + }; +} diff --git a/documents/업무/6월/3째주/temp.ts b/documents/업무/6월/3째주/temp.ts new file mode 100644 index 0000000..ea3ce98 --- /dev/null +++ b/documents/업무/6월/3째주/temp.ts @@ -0,0 +1,510 @@ +import { Subject } from 'rxjs'; +import { takeUntil, take } from 'rxjs/operators'; + +import { + Component, + OnInit, + OnDestroy, + ChangeDetectionStrategy, + ChangeDetectorRef, + Input, + Output, + EventEmitter, + NgZone +} from '@angular/core'; + +import { Store, select } from '@ngrx/store'; + +import { SortOrder } from '@ucap/core'; + +import { VersionInfo2Response } from '@ucap/api-public'; +import { LoginResponse } from '@ucap/protocol-authentication'; +import { + UserInfoSS, + DeptSearchType, + DeptUserRequest +} from '@ucap/protocol-query'; + +import { LogService } from '@ucap/ng-logger'; +import { + LoginSelector, + ConfigurationSelector +} from '@ucap/ng-store-authentication'; +import { QueryProtocolService } from '@ucap/ng-protocol-query'; +import { + DepartmentActions, + DepartmentSelector, + PresenceActions +} from '@ucap/ng-store-organization'; + +import { SearchData } from '../models/search-data'; + +const DEPT_ORDER_PROPERTY = 'order'; + +interface CheckedInfo { + checked: boolean; + userInfo: UserInfoSS; +} + +@Component({ + selector: 'app-organization-profile-list', + templateUrl: './profile-list.component.html', + styleUrls: ['./profile-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ProfileListComponent implements OnInit, OnDestroy { + @Input() + set searchData(data: SearchData) { + if (!this.loginRes) { + this._searchData = data; + return; + } + this.searchMember(data); + } + // tslint:disable-next-line: variable-name + private _searchData: SearchData; + + @Input() + selectedUser: UserInfoSS[]; + + @Input() + /** Cycle order of sorting by use ascending: undefined -> true -> false */ + set sortOrder(value: SortOrder) { + this._sortOrder = value; + this.userInfos = this.sort(this.userInfos); + } + get sortOrder() { + return this._sortOrder; + } + // tslint:disable-next-line: variable-name + _sortOrder: SortOrder = { + property: 'name', + ascending: undefined + }; + + @Output() + searched: EventEmitter = new EventEmitter(); + + @Output() + changedCheck: EventEmitter = new EventEmitter(); + + set userInfos(userInfos: UserInfoSS[]) { + this._userInfos = userInfos; + this.searched.emit(userInfos); + } + get userInfos() { + return this._userInfos; + } + // tslint:disable-next-line: variable-name + _userInfos: UserInfoSS[] = []; + + loginRes: LoginResponse; + versionInfo2Res: VersionInfo2Response; + + processing = false; + + private ngOnDestroySubject: Subject = new Subject(); + private myDeptDestroySubject: Subject; + + constructor( + private queryProtocolService: QueryProtocolService, + private store: Store, + private changeDetectorRef: ChangeDetectorRef, + private logService: LogService + ) {} + + ngOnInit(): void { + this.store + .pipe( + takeUntil(this.ngOnDestroySubject), + select(ConfigurationSelector.versionInfo2Response) + ) + .subscribe((versionInfo2Res) => { + this.versionInfo2Res = versionInfo2Res; + }); + + this.store + .pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes)) + .subscribe((loginRes) => { + this.loginRes = loginRes; + if (!!this._searchData) { + this.searchMember(this._searchData); + this._searchData = undefined; + } + }); + } + + ngOnDestroy(): void { + if (!!this.ngOnDestroySubject) { + this.ngOnDestroySubject.next(); + this.ngOnDestroySubject.complete(); + } + } + + checkAll() { + if (!this.userInfos || 0 === this.userInfos.length) { + return; + } + + const checked: CheckedInfo[] = []; + this.userInfos.forEach((u) => { + checked.push({ + checked: true, + userInfo: u + }); + }); + this.changedCheck.emit(checked); + } + + uncheckAll() { + if (!this.userInfos || 0 === this.userInfos.length) { + return; + } + + const unchecked: CheckedInfo[] = []; + this.userInfos.forEach((u) => { + unchecked.push({ + checked: false, + userInfo: u + }); + }); + this.changedCheck.emit(unchecked); + } + + /** 개별 체크여부 */ + getCheckedUser(userInfo: UserInfoSS) { + if (!!this.selectedUser && this.selectedUser.length > 0) { + return ( + this.selectedUser.filter((item) => item.seq === userInfo.seq).length > 0 + ); + } + return false; + } + + /** 개별선택(토글) 이벤트 */ + onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoSS }) { + this.changedCheck.emit([param]); + } + + onOpenProfile(userInfo: UserInfoSS): void { + alert('Open Profile'); + } + + private getMyDeptMember() { + this.myDeptDestroySubject = new Subject(); + + const req: DeptUserRequest = { + divCd: 'ORG', + companyCode: this.loginRes.companyCode, + seq: this.loginRes.departmentCode, + search: '', + searchRange: DeptSearchType.All, + senderCompanyCode: this.loginRes.companyCode, + senderEmployeeType: this.loginRes.userInfo.employeeType + }; + + this.processing = true; + + this.store + .pipe( + takeUntil(this.myDeptDestroySubject), + select(DepartmentSelector.myDepartmentUserInfoList) + ) + .subscribe( + (myDepartmentUserInfoList) => { + if (!myDepartmentUserInfoList) { + this.store.dispatch(DepartmentActions.myDeptUser({ req })); + return; + } + this._refreshUserInfos(myDepartmentUserInfoList); + + this.myDeptDestroySubject.next(); + this.myDeptDestroySubject.complete(); + this.myDeptDestroySubject = undefined; + }, + (error) => {}, + () => { + this.processing = false; + } + ); + } + + private sort(userInfos: UserInfoSS[]): UserInfoSS[] { + if (!userInfos || 0 === userInfos.length) { + return userInfos; + } + + const property = this.sortOrder.property; + const ascending = this.sortOrder.ascending; + let deptA: any; + let deptB: any; + let c: any; + let d: any; + + return userInfos.slice().sort((a, b) => { + try { + deptA = a[DEPT_ORDER_PROPERTY]; + deptB = b[DEPT_ORDER_PROPERTY]; + + if (undefined === ascending) { + return deptA < deptB + ? -1 + : deptA > deptB + ? 1 + : a[property] < b[property] + ? -1 + : a[property] > b[property] + ? 1 + : 0; + } + + c = ascending ? a[property] : b[property]; + d = ascending ? b[property] : a[property]; + + return c < d ? -1 : c > d ? 1 : 0; + } catch (error) { + console.log(error); + } + }); + } + + private searchMember(searchData: SearchData) { + if ( + !searchData || + (!searchData.bySearch && undefined === searchData.deptSeq) + ) { + this.getMyDeptMember(); + return; + } + + if (!!this.myDeptDestroySubject) { + this.myDeptDestroySubject.next(); + this.myDeptDestroySubject.complete(); + this.myDeptDestroySubject = undefined; + } + + let req: DeptUserRequest; + if (searchData.bySearch) { + req = { + divCd: 'ORGS', + companyCode: searchData.companyCode, + searchRange: DeptSearchType.All, + search: searchData.searchWord, + senderCompanyCode: this.loginRes.userInfo.companyCode, + senderEmployeeType: this.loginRes.userInfo.employeeType + }; + } else { + req = { + divCd: 'ORG', + companyCode: this.loginRes.companyCode, + seq: Number(searchData.deptSeq), + search: '', + searchRange: DeptSearchType.All, + senderCompanyCode: this.loginRes.companyCode, + senderEmployeeType: this.loginRes.userInfo.employeeType + }; + } + + this.processing = true; + this.queryProtocolService + .deptUser(req) + .pipe(take(1)) + .subscribe( + (data) => { + this._refreshUserInfos(data.userInfos); + }, + (error) => {}, + () => { + this.processing = false; + } + ); + } + + private _refreshUserInfos(userInfos: UserInfoSS[]) { + this.userInfos = this.sort(userInfos); + + // 검색 결과에 따른 프레즌스 조회. + const userSeqList: string[] = userInfos.map((user) => user.seq); + + if (userSeqList.length > 0) { + this.store.dispatch( + PresenceActions.bulkInfo({ + divCd: 'orgSrch', + userSeqs: userSeqList + }) + ); + } + } +} + + +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { + Component, + OnInit, + OnDestroy, + ChangeDetectionStrategy, + ChangeDetectorRef, + Input +} from '@angular/core'; + +import { Store, select } from '@ngrx/store'; + +import { VersionInfo2Response } from '@ucap/api-public'; +import { UserInfoSS } from '@ucap/protocol-query'; + +import { LogService } from '@ucap/ng-logger'; +import { PresenceSelector } from '@ucap/ng-store-organization'; +import { StatusBulkInfo } from '@ucap/protocol-status'; + +@Component({ + selector: 'app-organization-profile-image-01', + templateUrl: './profile-image-01.component.html', + styleUrls: ['./profile-image-01.component.scss'] +}) +export class ProfileImage01Component implements OnInit, OnDestroy { + @Input() + set userInfo(userInfo: UserInfoSS) { + this._userInfo = userInfo; + } + get userInfo(): UserInfoSS { + return this._userInfo; + } + _userInfo: UserInfoSS; + + @Input() + versionInfo: VersionInfo2Response; + + presenceInfo: StatusBulkInfo; + + private ngOnDestroySubject: Subject = new Subject(); + + constructor( + private store: Store, + private changeDetectorRef: ChangeDetectorRef, + private logService: LogService + ) {} + + ngOnInit(): void { + this.store + .pipe( + takeUntil(this.ngOnDestroySubject), + select( + PresenceSelector.selectStatusBulkInfo, + Number(this.userInfo?.seq) + ) + ) + .subscribe((status) => { + this.presenceInfo = status; + }); + } + + ngOnDestroy(): void { + if (!!this.ngOnDestroySubject) { + this.ngOnDestroySubject.next(); + this.ngOnDestroySubject.complete(); + } + } +} + + +label, +contextmenu, + profile, + group +confirm, +error, + +{ + "label": { + "organization": "조직도", + "selectedUsers": "선택한 대화상대", + "addGroup": "그룹추가", + "chat": "대화", + "message": "쪽지", + "call": "전화", + "videoConference": "화상", + "searchResult": "검색결과", + "sortName": "이름" + }, + "presence": { + "offline": "오프라인", + "online": "온라인", + "away": "부재중", + "statusMessage1": "다른용무중", + "statusMessage2": "회의중", + "statusMessage3": "집중근무중" + } +} + + +{ + "label": { + "confirmRemoveBuddy": "선택한 멤버를 삭제하시겠습니까?\n해당 그룹에서만 선택하신 멤버가 삭제됩니다." + }, + "category": { + "favorite": "즐겨찾기", + "default": "기본", + "myDept": "소속부서" + }, + "moreMenu": { + "show": { + "all": "전체 보기", + "onlineBuddy": "접속한 동료만 보기", + "onOff": "온/오프라인 보기" + }, + "group": { + "addNew": "새 그룹 추가", + "expandMore": "그룹 전체 열기", + "expandLess": "그룹 전체 닫기", + "changeOrder": "그룹 순서 바꾸기", + "startChatWithGroup": "그룹 대화하기", + "sendMessageToGroup": "그룹 쪽지 보내기", + "groupMemberManagement": "그룹 멤버 관리", + "changeGroupName": "그룹 이름 바꾸기", + "removeGroup": "그룹 삭제" + }, + "profile": { + "open": "프로필 보기", + "unfavorite": "즐겨찾기 해제", + "favorite": "즐겨찾기 등록", + "nickname": "닉네임 설정", + "moveBuddy": "대화상대 이동", + "copyBuddy": "대화상대 복사", + "removeBuddy": "이 그룹에서 삭제" + }, + "confirm": { + "removeGroup": "그룹을 삭제하시겠습니까?
그룹 멤버는 해당 그룹에서만 삭제됩니다." + }, + "error": { + "label": "그룹 에러", + "requireName": "그룹명은 필수입력입니다.", + "invalidName": "유효하지 않은 그룹명입니다.", + "invalidSelectedUser": "선택된 유저가 존재하지 않습니다." + } + }, + + "profile": { + "labels": { + "myProfile": "내 프로필", + "company": "회사", + "email": "이메일", + "linePhoneNumber": "사무실", + "mobilePhoneNumber": "핸드폰", + "department": "부서", + "mytalk": "MyTalk", + "setting": "환경설정", + "chat": "대화", + "sms": "SMS", + "videoConference": "화상회의", + "message": "쪽지", + "nickname": "닉네임 미설정" + }, + "fields": { + "intro": "인트로" + }, + "errors": {} + } +} diff --git a/documents/업무/6월/4째주/0622.txt b/documents/업무/6월/4째주/0622.txt new file mode 100644 index 0000000..257e98d --- /dev/null +++ b/documents/업무/6월/4째주/0622.txt @@ -0,0 +1,40 @@ +기획 문의 + 그룹복사, 그룹이동 시 그룹 이름과 사용자들을 선택 시 -> 그룹생성으로 간주? 아니면 그룹생성 그룹 복사 둘다? 문의 + + + + + _ngcontent-laf-c391 + +
+ + +{StatusCode: "500", ErrorMessage: "empty UserSeq", ProfileURL: "", ProfileSubDir: "", Intro: ""} +ErrorMessage: "empty UserSeq" +Intro: "" +ProfileSubDir: "" +ProfileURL: "" +StatusCode: "500" + + +554, 773966 + + + + +701307 +476791 +8890 +677714 diff --git a/documents/업무/6월/4째주/0623.txt b/documents/업무/6월/4째주/0623.txt new file mode 100644 index 0000000..a285a28 --- /dev/null +++ b/documents/업무/6월/4째주/0623.txt @@ -0,0 +1,102 @@ +프로필 이미지 + 리듀서 + loginRes 업데이트 + 액션 + 프로필 변경 액션 정의 + notification 액션 정의 + + 이펙트 + 대화방 프로필 이미지 업데이트 + 대상 RoomType: bot, single + 대화방 유저 리스트 프로필 이미지 업데이트 + + 대화방 리스트, 대화방 유저 프로필 이미지 + roomUsersShort.userInfos + + 동료 프로필 이미지 업데이트 + BuddySelector.buddies + + 동료, 대화방 프로필 이미지 스테이트 확인 + + 자신 프로필 변경 + 스토어 변경 + 동료 프로필 변경 알림 + 동료, 대화방 프로필 변경 + +프로필 변경 데이터 + + +updateUserInfoNoti + +updateProfileImageNoti + + updateBuddyProfile + +대화방 + user seq find -> room info -> userList||userShort -> update + + + +this.store.pipe(select(RoomSelector.rooms)), +this.store.pipe(select(RoomSelector.roomUsers)), +this.store.pipe(select(RoomSelector.roomUsersShort)) + +roomUsers = (roomUsers || []).filter( + (userMap) => + rooms.findIndex((roomInfo) => roomInfo.roomId === userMap.roomId) > + -1 +); +roomUsersShort = (roomUsersShort || []).filter( + (userMap) => + rooms.findIndex((roomInfo) => roomInfo.roomId === userMap.roomId) > + -1 +); + +const recommendedWordList = []; +for (const r of rooms) { + if (!!r.roomName && '' !== r.roomName.trim()) { + recommendedWordList.push(r.roomName); + } +} +for (const ru of roomUsers) { + for (const u of ru.userInfos) { + if (!!this.loginRes && u.seq !== Number(this.loginRes.userSeq)) { + if (!!u.name && '' !== u.name.trim() && u.isJoinRoom) { + recommendedWordList.push(u.name); + } + } + } +} +for (const ru of roomUsersShort) { + for (const u of ru.userInfos) { + if (!!this.loginRes && u.seq !== Number(this.loginRes.userSeq)) { + if (!!u.name && '' !== u.name.trim() && u.isJoinRoom) { + recommendedWordList.push(u.name); + } + } + } +} +this.recommendedWordList = [ + ...recommendedWordList.filter( + (item, index) => recommendedWordList.indexOf(item) === index + ) +]; + +auth 12 +group 17 +org 12 +chat 44 + + +const profile = { + userSeq: this.loginRes.userSeq + '', + deviceType: 'W', + token: this.loginRes.tokenString, + file: profileImageFileUploadItem.file, + fileUploadItem: profileImageFileUploadItem +} as FileProfileSaveRequest; + +this.appFileServie.fileProfileSave( + profile, + this.versionInfo2Res.profileUploadUrl +); \ No newline at end of file diff --git a/documents/업무/6월/4째주/0624.txt b/documents/업무/6월/4째주/0624.txt new file mode 100644 index 0000000..6f94f04 --- /dev/null +++ b/documents/업무/6월/4째주/0624.txt @@ -0,0 +1,39 @@ +const findIdx = noti.info.indexOf('ProfileImage'); +let imgInfo: string = noti.info; + +if (findIdx > -1) { + const startIdx = noti.info.indexOf('/', findIdx); + imgInfo = noti.info.substring(startIdx); +} + +const roomInfo1 = rooms.filter( + (r) => r.roomId === ru.roomId +)[0]; +const cUser = { + ...u, + profileImageFile: 'imgInfo' +}; + +const idx = ru.userInfos.findIndex( + (u3) => Number(u3.seq) === Number(u.seq) +); +if (idx > -1) { + ru.userInfos[idx] = cUser; +} +const tempShort: UserInfoShort[] = []; +ru.userInfos.map((u2) => { + if (Number(u2.seq) === Number(u.seq)) { + tempShort.push(cUser); + } else { + tempShort.push(u2); + } +}); +const tempUserShort = [...ru.userInfos, cUser]; + +tempRoomList.push({ + roomInfo: roomInfo1, + userInfoS: tempShort +}); + +/2020/06/24/PF_338127_103928272.jpg + diff --git a/documents/업무/6월/4째주/0625.txt b/documents/업무/6월/4째주/0625.txt new file mode 100644 index 0000000..e76c2ec --- /dev/null +++ b/documents/업무/6월/4째주/0625.txt @@ -0,0 +1 @@ +즐겨찾기 구성원을 모두 해제 시 즐겨찾기 그룹 없어지지 않음 diff --git a/documents/업무/6월/4째주/0626.txt b/documents/업무/6월/4째주/0626.txt new file mode 100644 index 0000000..18c698c --- /dev/null +++ b/documents/업무/6월/4째주/0626.txt @@ -0,0 +1,124 @@ +this.mediaObserver + .asObservable() + .pipe(takeUntil(this.ngOnDestroySubject)) + .subscribe((changes) => { + if (!changes || 0 === changes.length) { + return; + } + for (const change of changes) { + switch (change.mqAlias) { + case 'lt-sm': + this.layoutMode = 'min'; + this.changeDetectorRef.detectChanges(); + return; + case 'sm': + case 'md': + this.layoutMode = 'mid'; + this.changeDetectorRef.detectChanges(); + return; + case 'gt-md': + this.layoutMode = 'max'; + this.changeDetectorRef.detectChanges(); + return; + default: + break; + } + } + }); +} + +대화 이슈 + 리스트 + 백 스페이스로 입력된 검색어 모두 삭제 시 기존 리스트를 출력 하지 않음 + 대화 + 폼 컴포넌트 입력창 간헐적으로 입력이 안됨 + -> 한글일 때 키보드 연속으로 누르고 있을 때 화면에 나타나지 않다가 key up 할때 한번에 입력 + 번역 + 간략보기 기능 미구현 + 대화방 멤버 + me 표시 없음 + 프레즌스 표현안됨 + 컨텍스트 메뉴 (미구현) + 프로필, 대화, 쪽지 + 삭제, 회수 + 모바일, 피시 간 연동 안됨, 상대방 대화에서 회수되지 않음(방이동 이나 새로고침) + + 다이얼로그 + 일반 대화방 생성 + -> 인원 선택 X 대화방 생성 버튼 활성화 + 타이머 대화방 상동 + 1:n 대화방 생성 후 '대화방 이름 설정 안내 팝업' 노출되지 않음 + 대화 x + type(pin):"J" + senderSeq(pin):"770074" + + 타이머 설정 안내 팝업 노출되지 않음 + + +
+
+
+ {{ + 'chat:dialog.roomName' | ucapI18n + }} + + + {{ input.value?.length || 0 }}/20 + +
+
+ {{ + 'chat:dialog.roomNameChangeTarget' | ucapI18n + }} + + {{ + 'chat:dialog.me' | ucapI18n + }} + {{ + 'chat:dialog.all' | ucapI18n + }} + + +
+
+ {{ + 'chat:dialog.settingTimer' | ucapI18n + }} + + + + {{ timer.text }} + + + {{ + 'chat:dialog:settingTimerHint' | ucapI18n + }} + +
+
+
\ No newline at end of file diff --git a/documents/업무/6월/4째주/temp.txt b/documents/업무/6월/4째주/temp.txt new file mode 100644 index 0000000..b5fca2f --- /dev/null +++ b/documents/업무/6월/4째주/temp.txt @@ -0,0 +1,183 @@ +import { + Component, + OnInit, + OnDestroy, + ChangeDetectionStrategy, + ChangeDetectorRef, + Input, + EventEmitter, + Output +} from '@angular/core'; + +import { Subject, combineLatest, merge } from 'rxjs'; +import { Store, select } from '@ngrx/store'; +import { takeUntil } from 'rxjs/operators'; + +import { LoginResponse } from '@ucap/protocol-authentication'; +import { + RoomInfo, + UpdateRequest, + UpdateTimerSetRequest +} from '@ucap/protocol-room'; +import { RoomSelector, RoomActions } from '@ucap/ng-store-chat'; +import { LoginSelector } from '@ucap/ng-store-authentication'; +import { I18nService } from '@ucap/ng-i18n'; +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-drawer-chat-setting', + templateUrl: './setting.drawer.component.html', + styleUrls: ['./setting.drawer.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SettingDrawerComponent implements OnInit, OnDestroy { + private roomIdSubject = new Subject(); + private ngOnDestroySubject = new Subject(); + + @Input() + set roomId(value: string) { + this._roomId = value; + this.roomIdSubject.next(value); + this._initializeData(); + } + get roomId(): string { + return this._roomId; + } + // tslint:disable-next-line: variable-name + _roomId: string; + + @Output() + closed = new EventEmitter(); + + loginRes: LoginResponse; + roomInfo: RoomInfo; + + roomName: string; + timerArray: { value: number; text: string }[]; + + chatSettingForm: FormGroup; + + constructor( + private i18nService: I18nService, + private store: Store, + private formBuilder: FormBuilder, + private changeDetectorRef: ChangeDetectorRef + ) {} + + ngOnInit(): void { + this._initializeData(); + + this.i18nService.languageChanged$ + .pipe(takeUntil(this.ngOnDestroySubject)) + .subscribe((_) => { + this.setTimerArray(); + }); + this.setTimerArray(); + } + + ngOnDestroy(): void { + if (!!this.ngOnDestroySubject) { + this.ngOnDestroySubject.next(); + this.ngOnDestroySubject.complete(); + } + } + + private _initializeData() { + combineLatest([ + this.store.pipe(select(LoginSelector.loginRes)), + this.store.pipe(select(RoomSelector.room, this.roomId)) + ]) + .pipe(takeUntil(merge(this.ngOnDestroySubject, this.roomIdSubject))) + .subscribe(([loginRes, roomInfo]) => { + this.loginRes = loginRes; + this.roomInfo = roomInfo; + + this.chatSettingForm = this.formBuilder.group({ + roomName: [ + this.roomInfo?.roomName, + !this.roomInfo?.isTimeRoom ? [Validators.required] : [] + ], + changeTarget: ['me'], + timerInterval: [this.roomInfo?.timeRoomInterval] + }); + + this.changeDetectorRef.detectChanges(); + }); + } + + onChange() { + const checkInvalid = this.chatSettingForm.invalid; + let roomName: string; + if (checkInvalid) { + roomName = ''; + } else { + roomName = this.chatSettingForm.get('roomName').value; + } + } + + onKeyupName() { + this.chatSettingForm.get('roomName').markAsTouched(); + } + + setTimerArray() { + const hourFrom = this.i18nService.t('common:units.hourFrom'); + const minute = this.i18nService.t('common:units.minute'); + const second = this.i18nService.t('common:units.second'); + + this.timerArray = [ + { value: 5, text: `5 ${second}` }, + { value: 10, text: `10 ${second}` }, + { value: 30, text: `30 ${second}` }, + { value: 60, text: `1 ${minute}` }, + { value: 300, text: `5 ${minute}` }, + { value: 600, text: `10 ${minute}` }, + { value: 1800, text: `30 ${minute}` }, + { value: 3600, text: `1 ${hourFrom}` }, + { value: 21600, text: `6 ${hourFrom}` }, + { value: 43200, text: `12 ${hourFrom}` }, + { value: 86400, text: `24 ${hourFrom}` } + ]; + } + + onChangeGroupName(name: string) { + this.roomName = name; + } + + onClosed(event: MouseEvent): void { + this.closed.emit(); + } + + const forbidden = /[\{\}\[\]\/?.;:|\)*~`!^+<>@\#$%&\\\=\(\'\"]/g.test( + inputValue + ); + + onConfirm(): void { + const roomName = this.chatSettingForm.get('roomName').value; + const roomNameChangeTarget = this.chatSettingForm.get('changeTarget').value; + const timerInterval = this.chatSettingForm.get('timerInterval').value; + + this.store.dispatch( + RoomActions.update({ + req: { + roomId: this.roomInfo.roomId, + roomName, + receiveAlarm: this.roomInfo.receiveAlarm, + syncAll: roomNameChangeTarget.toUpperCase() === 'ALL' ? true : false + } as UpdateRequest + }) + ); + + if (!!this.roomInfo?.isTimeRoom) { + this.store.dispatch( + RoomActions.updateTimeRoomInterval({ + req: { + roomId: this.roomInfo.roomId, + timerInterval + } as UpdateTimerSetRequest + }) + ); + } + + this.closed.emit(); + } +} diff --git a/documents/업무/6월/4째주/ucap-0626.zip b/documents/업무/6월/4째주/ucap-0626.zip new file mode 100644 index 0000000..1985768 Binary files /dev/null and b/documents/업무/6월/4째주/ucap-0626.zip differ diff --git a/documents/업무/6월/4째주/ucap-angular-0626.zip b/documents/업무/6월/4째주/ucap-angular-0626.zip new file mode 100644 index 0000000..1842159 Binary files /dev/null and b/documents/업무/6월/4째주/ucap-angular-0626.zip differ diff --git a/documents/업무/6월/4째주/ucap-lg-web-0626.zip b/documents/업무/6월/4째주/ucap-lg-web-0626.zip new file mode 100644 index 0000000..1baf843 Binary files /dev/null and b/documents/업무/6월/4째주/ucap-lg-web-0626.zip differ diff --git a/weekly-report/6월/주간보고_박병은_2020.0619.pptx b/weekly-report/6월/주간보고_박병은_2020.0619.pptx new file mode 100644 index 0000000..ca48345 Binary files /dev/null and b/weekly-report/6월/주간보고_박병은_2020.0619.pptx differ diff --git a/weekly-report/6월/주간보고_박병은_2020.0626.pptx b/weekly-report/6월/주간보고_박병은_2020.0626.pptx new file mode 100644 index 0000000..5f3ab9c Binary files /dev/null and b/weekly-report/6월/주간보고_박병은_2020.0626.pptx differ