This commit is contained in:
2025-07-02 21:55:07 +09:00
commit fa63330e69
855 changed files with 432271 additions and 0 deletions

View File

@@ -0,0 +1,762 @@
import m from 'http://talk.kospo.co.kr:3000/static/bundle/mithril-2.2.2/mithril.js'
import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js";
import {talkEvent} from "http://talk.kospo.co.kr:3000/static/js/module/talkEvent.js";
import {talkMapping, messageMapping} from "http://talk.kospo.co.kr:3000/static/js/module/render.js"
import {Tab} from "http://talk.kospo.co.kr:3000/static/bundle/bootstrap-5.1.3/js/bootstrap.esm.js";
import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js";
import {HubEvent} from "http://talk.kospo.co.kr:3000/static/js/module/hubEvent.js";
import {showNotification} from "http://talk.kospo.co.kr:3000/static/js/notification.js";
import receiver from "http://talk.kospo.co.kr:3000/static/js/module/receiver.js";
// api 관리
let isQuestion = true;
const talkInit = () => {
work().then(() => {
manual().then(() => {
question()
})
docManual()
videoManual()
})
}
// 현재 사용자 정보
const getUser = async () => {
global.user = await global.request({
url: `/api/user/info/client`,
method: 'get',
withCredentials: true
})
}
// itsm 만족도 조사 저장
const setITSMSatis = (talkId, reqId, rating, content) => {
global.request({
url: `/api/ict/satis`,
method: 'post',
body: {talk_id : talkId, req_id : reqId, h_point: rating, opinion: content},
withCredentials: true
})
}
// scm 만족도 조사 저장
const setSCMSatis = (talkId, reqId, rating, content) => {
global.request({
url: `/api/scm/satis`,
method: 'post',
body: {talk_id : talkId, req_id : reqId, h_point: rating, opinion: content},
withCredentials: true
})
}
// 접속 중인 시스템 정보
const work = async () => {
global.work = await global.request({
url: `/api/work`,
method: 'get',
params: {workId: global.currentWorkId},
withCredentials: true
})
global.shadowRoot.querySelector('#intro-work').innerText = global.work.workNm;
global.shadowRoot.querySelector('#intro-online').classList.add(global.work.onlineYn ? 'online' : 'offline');
global.shadowRoot.querySelector('#intro-user').innerText = global.user.name;
receiver.changeLoginInfo(global.work)
}
// 접속 중인 시스템의 매뉴얼
const manual = () => {
// 현재 업무의 메뉴얼 & 비디오 메뉴얼 호출
return new Promise((resolve, reject) => {
global.request({
method: 'get',
url: `/api/manual/intro`,
params: {workId: global.work.workId},
withCredentials: true
}).then((images) => {
const manualSlide = global.shadowRoot.querySelector('#manual-play');
const vNode = []
if(images.length === 0) {
const parent = Common.findParentElement(manualSlide, 'mt-4')
parent.remove()
isQuestion = false;
} else {
images.forEach((i, idx) => {
if (i.onm.includes("mp4")) {
vNode.push(
m('div', {class: `carousel-item ${idx === 0 ? 'active' : ''}`}, [
m('video', {
controls: false,
class: 'd-block w-100 intro-video',
muted: true,
preload: 'auto',
autoplay: false
}, [
m('source', {
src: `${global.apiUrl}/api/manual/view/video?id=${i.id}&type=S`,
type: "video/mp4"
})
]),
m('div', {class: 'video-control'}, [
m('div', {class:'video-fullscreen cus-hide', 'data-ori-src': `${global.apiUrl}/api/manual/view/video?id=${i.id}&type=O`}, [
m('i', {class: 'bi-fullscreen bi-color-white'})
])
])
])
)
} else {
vNode.push(
m('div', {class: `carousel-item ${idx === 0 ? 'active' : ''}`}, [
m('img', {
src: `${global.apiUrl}/api/manual/view/image?workId=${global.work.workId}&vnm=${i.vnm}&sabun=${global.user.sabun}`,
class: 'd-block w-100',
alt: 'img1'
})
])
)
}
})
m.render(manualSlide.querySelector('.carousel-inner'), vNode);
/* 숏츠 비디오 이벤트 정의 */
global.shadowRoot.querySelectorAll('.video-control').forEach((target) => {
target.addEventListener('mouseenter', () => {
target.querySelector('.video-fullscreen').classList.remove('cus-hide')
target.querySelector('.video-fullscreen').classList.add('cus-show')
})
target.addEventListener('mouseleave', () => {
target.querySelector('.video-fullscreen').classList.remove('cus-show')
target.querySelector('.video-fullscreen').classList.add('cus-hide')
})
})
global.shadowRoot.querySelectorAll('.video-fullscreen').forEach((target) => {
target.addEventListener('click', () => {
const oriSrc = target.dataset.oriSrc
console.log(oriSrc)
const fullvideo = global.shadowRoot.querySelector('#fullscreen-container');
fullvideo.classList.remove('cus-hide')
fullvideo.classList.add('cus-show');
const video = m('video', {preload: 'none', controls: 'controls', id: 'fullvideo', style: 'width:100%; height:100%;'}, [
m('source', {src: oriSrc, type: 'video/mp4'})
])
m.render(fullvideo, video);
const playVideo = global.shadowRoot.querySelector('#fullvideo');
playVideo.requestFullscreen();
playVideo.play();
window.onresize = () => {
if(window.matchMedia('(display-mode: fullscreen)').matches || window.document.fullscreenElement) {
console.log(true)
} else {
closeFullscreen();
console.log(false);
}
}
})
})
}
resolve();
})
})
}
const closeFullscreen = () => {
const playVideo = global.shadowRoot.querySelector('#fullvideo');
if(playVideo) {
const fullvideo = global.shadowRoot.querySelector('#fullscreen-container');
m.render(fullvideo, []);
fullvideo.classList.remove('cus-show')
fullvideo.classList.add('cus-hide')
}
}
// 접속 중인 시스템의 자주 하는 질문
const question = () => {
const questionCnt = isQuestion ? 5 : 6;
/*현재 업무의 자주하는 질문 설정 */
global.request({
method: 'get',
url: `/api/question/${global.work.workId}`,
withCredentials: true
}).then((question) => {
const questionContent = global.shadowRoot.querySelector('#question');
const question_page = Math.ceil(question.length / questionCnt)
let question_div = null
let paging = 0;
question.forEach((a, idx) => {
if(idx % questionCnt === 0) {
paging++;
question_div = document.createElement('div')
question_div.setAttribute("id", `question-pg-${paging}`)
question_div.classList.add('question-pg-container')
if(paging !== 1) {
question_div.classList.add('cus-hide')
} else {
question_div.classList.add('cus-show')
}
}
const questionP = document.createElement("p");
questionP.classList.add('cursor-pointer', 'question')
const questionText = document.createTextNode(`${a.content}`)
questionP.appendChild(questionText)
question_div.append(questionP);
questionP.addEventListener('click', () => {
const talkId = talkEvent.generateUUID();
// 키보드 숨김 해제
global.element.chatEditorArea.classList.remove('cus-hide');
// 채팅 구독 메시지 보내기
localStorage.setItem(global.tabId, talkId)
// 발 생성자 주입
global.chatCreator = global.tabId;
talkEvent.join(global.talkParams({
type: 'JOIN',
message: a.content,
talkId: talkId,
workId: global.work.workId,
introOwner: 'mine'
}))
talkEvent.messageShow()
})
if(idx % questionCnt === questionCnt-1 || idx === question.length-1) {
questionContent.append(question_div)
}
})
const pagination = document.createElement('div');
pagination.classList.add('fx', 'fx-gap')
pagination.setAttribute("id", 'question_pg')
for(var i=0; i< question_page; i++) {
const pagination_btn = document.createElement('div')
if(i === 0) {
pagination_btn.classList.add('btn', 'active')
pagination_btn.dataset.pg = i
} else {
pagination_btn.classList.add('btn')
pagination_btn.dataset.pg = i
}
pagination.append(pagination_btn)
}
questionContent.append(pagination)
let current_page = 0
function switchToNext(evt) {
const {target} =evt;
if(!target.classList.contains('btn')) {
return;
}
const clickedBtn = target;
if(clickedBtn.classList.contains('active')) {
return;
}
const activeBtn = pagination.getElementsByClassName('active')[0]
activeBtn?.classList.remove("active")
clickedBtn.classList.add('active')
global.shadowRoot.querySelectorAll(".question-pg-container").forEach((el) => {
el.classList.add('cus-hide')
el.classList.remove('cus-show')
});
const active = global.shadowRoot.querySelector(`#question-pg-${Number(clickedBtn.dataset.pg) + 1}`)
active.classList.remove('cus-hide')
active.classList.add('cus-show')
current_page = Number(clickedBtn.dataset.pg) + 1;
}
pagination.addEventListener('click', switchToNext)
/*자주찾는 질문이 2페이지 이상일때만 실행*/
if(question_page > 1) {
setInterval(autoNext, 10000)
function autoNext() {
let movePage = Number(current_page) + 1
if(question_page < movePage) movePage = 1;
global.shadowRoot.querySelectorAll(".question-pg-container").forEach((el) => {
el.classList.add('cus-hide')
el.classList.remove('cus-show')
});
const active = global.shadowRoot.querySelector(`#question-pg-${movePage}`);
active.classList.remove('cus-hide')
active.classList.add('cus-show')
current_page = movePage;
}
}
if(!isQuestion) {
const question = global.shadowRoot.querySelector('#question');
const questionPg = global.shadowRoot.querySelector('.question-pg-container');
question.style.minHeight = '286px';
questionPg.style.minHeight = '230px';
}
})
}
// 접속 중인 시스템의 문서 매뉴얼
const docManual = () => {
/*본인 메뉴얼*/
global.request({
method: 'get',
url: `/api/manual`,
params: {workId: global.work.workId, type: '0000'},
withCredentials: true
}).then((manuals) => {
const manualVNode = [];
manuals.map((ma) => {
manualVNode.push(
m('div', {class: "d-flex justify-content-start manual-content"}, [
m('div', {class: "p-2 text-ellipsis", style: "width:60%;cursor: help;", title:ma.onm}, `${ma.onm}`),
m('div', {class: "p-2", style: "width:20%;"}, `${ma.version}`),
m('a', {
href: `${global.apiUrl}/api/manual/download/doc?workId=${ma.workId}&vnm=${ma.vnm}`,
target: '_download_',
rel: 'noopener',
style: 'padding-top:6px;'
}, [
m('i', {
class: "bi bi-download text-black",
style: "padding-right:10px; font-size:1.0rem; cursor:pointer;"
})
])
])
)
})
const manualBody = global.shadowRoot.querySelector('#manual-doc-body');
const content = manualBody.querySelector('.simplebar-content');
if(manualVNode.length > 0) m.render(content, manualVNode)
})
}
// 접속 중인 시스템의 동영상 매뉴얼
const videoManual = () => {
global.request({
method: 'get',
url: `/api/manual/video`,
params: {workId: global.work.workId},
withCredentials: true
}).then((manuals) => {
const manualVNode = [];
manuals.map((ma) => {
manualVNode.push(
m('div', {class: "d-flex justify-content-evenly manual-content"}, [
m('div', {class: "p-2 text-ellipsis", style: "width:70%;"}, `${ma.onm}`),
// m('div', {class: "p-2", style: "font-size:13px; width:20%;"}, `${ma.version}`),
m('button', {
class: 'btn btn-sm btn-play manual-play-btn p-0',
'data-id': ma.id,
}, '재생')
])
)
})
const manualBody = global.shadowRoot.querySelector('#manual-video-body');
const content = manualBody.querySelector('.simplebar-content');
if(manualVNode.length > 0) m.render(content, manualVNode)
// videoManualPlayEvent();
})
console.log('work init end')
}
// 생성된 톡방 목록 추가
const setChatList = function (chat) {
console.log('setChatList before', global.talkData, chat)
global.talkData.unshift(chat)
console.log('setChatList after', global.talkData)
// 채팅 목록 생성
talkMapping(global.talkData);
// 채팅 목록 구독
if (Common.isMaster()) {
chatConnect([chat]);
}
// 채팅 부트스트랩 이벤트 수동 연결
chatBootstrapEvent();
talkEvent.badgeChange()
}
// 현사용자의 톡방 목록
const getTalkList = function (reset) {
return new Promise((resolve, reject) => {
global.request({
url: `/api/talk`,
method: 'get',
withCredentials: true
}).then((lists) => {
if (reset) {
global.talkData = lists;
getTalkListEvent()
resolve(global.talkData.length === 0 ? true : false)
} else {
lists.forEach(list => {
if (!global.talkData.map(talk => talk.talkId).join(',').includes(list.talkId)) {
global.talkData.push(list)
}
})
getTalkListEvent()
resolve(global.talkData.length === 0 ? true : false)
}
}).catch(function (error) {
console.log(error)
reject()
})
})
}
// 톡방 이벤트 정의 소켓 연결 및 동적으로 생성된 DOM 이벤트 재설정
const getTalkListEvent = () => {
// 채팅 목록 생성
talkMapping(global.talkData);
// 마스터만 채팅 목록 구독
if (Common.isMaster()) {
chatConnect(global.talkData);
}
// 채팅 부트스트랩 이벤트 수동 연결
chatBootstrapEvent();
talkEvent.badgeChange()
}
const getApInfo = () => {
return new Promise((resolve, reject) => {
global.request({
url: `/api/getApInfo`,
method: 'get',
withCredentials: true
}).then(data => {
console.log(data)
resolve(data);
}).catch(() => {
reject();
})
})
}
// 소켓 구독
const chatConnect = function (chats) {
for (const ch of chats) {
if (!ch.closeYn) {
if (!Object.keys(global.subscribeList).includes(ch.talkId)) {
global.subscribeList[ch.talkId] = talkEvent.subscribe(ch.talkId)
}
}
}
}
// 톡방 이벤트 정의
const chatBootstrapEvent = () => {
/*bootstrap 수동 이벤트 설정*/
global.shadowRoot.querySelectorAll('div[data-bs-toggle="tab"]').forEach((el) => {
if (!el.dataset.tabListener) {
const tabTrigger = new Tab(el);
el.addEventListener('click', function (e) {
e.preventDefault();
tabTrigger.show();
})
}
el.dataset.tabListener = true;
})
}
// 톡방 클릭시 해당 메시지
const getMessage = function (messageParams) {
global.request({
url: `/api/message/line`,
method: 'get',
params: messageParams,
withCredentials: true
}).then((dto) => {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === messageParams.talkId)[0];
cacheTalk.messageParams = messageParams;
cacheTalk.talkMessages = dto;
});
}
/*
* 비동기 톡방 메시지 호출
* parameter
* reset : 초기 설정 일시 true 재연결시 false
* */
const getMessageAll = async function (reset) {
const dto = await global.request({
url: `/api/message/all`,
method: 'get',
withCredentials: true
});
if (reset) {
global.talkData.forEach((talk) => {
const cacheTalk = dto.filter((talkData) => talkData.talkId === talk.talkId)[0];
talk.talkMessages = cacheTalk.talkMessages;
})
} else {
let queue = []
global.talkData.forEach((talk) => {
try {
const lastMsg = talk.talkMessages.talks[talk.talkMessages.talks.length - 1]
const cacheTalk = dto.filter((talkData) => talkData.talkId === talk.talkId)[0];
const newMsg = cacheTalk.talkMessages.talks.filter((ct) => {
return Common.dateDifference(new Date(ct.insDate), new Date(lastMsg.insDate))
})
if (newMsg.length > 0) {
newMsg.forEach((msg) => {
msg.workNm = talk.work.workNm
})
talk.lastMessage = newMsg[newMsg.length - 1].message;
talk.lastMessageDate = newMsg[newMsg.length - 1].insDate;
// 톡방 접속중인 경우 메시지 맵핑
if (localStorage.getItem(global.tabId) === talk.talkId) {
messageMapping(talk.talkId, {talks: newMsg}, 'after', false)
// 브라우저 상태가 hidden 인 경우 알림에 추가
if (!document.hasFocus()) queue = [...queue, ...newMsg]
// 그외 메시지 재정의
} else {
talk.talkMessages.talks = [...newMsg, ...talk.talkMessages.talks]
talk.unReadCnt = talk.unReadCnt + newMsg.length;
queue = [...queue, ...newMsg]
}
}
} catch (e) {
console.log(`talk.talkId is null messages`)
}
})
console.log(queue)
// 추가된 큐가 존재 할시 톡방 저체 갱신
// 큐에 정의된 메시지를 알림
if (queue.length > 0) {
talkMapping(global.talkData);
talkEvent.badgeChange();
queue.forEach((que) => {
showNotification(que)
})
}
}
}
const getMoreMessageAll = async function () {
let insDate = '1999-01-01';
global.talkData.forEach(talk => {
if(insDate < talk.lastMessageDate) {
insDate = talk.lastMessageDate
}
})
const dtos = await global.request({
url: `/api/message/more/all`,
method: 'get',
params: {'insDate': insDate},
withCredentials: true
});
let queue = []
dtos.forEach((dto) => {
try {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === dto.talkId)[0];
const newMsg = dto.talkMessages.talks;
console.log(newMsg)
if (newMsg.length > 0) {
newMsg.forEach((msg) => {
msg.workNm = cacheTalk.work.workNm
})
cacheTalk.lastMessage = newMsg[newMsg.length - 1].message;
cacheTalk.lastMessageDate = newMsg[newMsg.length - 1].insDate;
// 톡방 접속중인 경우 메시지 맵핑
if (localStorage.getItem(global.tabId) === cacheTalk.talkId) {
messageMapping(cacheTalk.talkId, {talks: newMsg}, 'after', false)
// 브라우저 상태가 hidden 인 경우 알림에 추가
if (!document.hasFocus()) queue = [...queue, ...newMsg]
// 그외 메시지 재정의
} else {
cacheTalk.talkMessages.talks = [...newMsg, ...cacheTalk.talkMessages.talks]
cacheTalk.unReadCnt = cacheTalk.unReadCnt + newMsg.length;
queue = [...queue, ...newMsg]
}
}
} catch (e) {
console.log(`talk.talkId is null messages`)
}
})
// 추가된 큐가 존재 할시 톡방 저체 갱신
// 큐에 정의된 메시지를 알림
if (queue.length > 0) {
talkMapping(global.talkData);
talkEvent.badgeChange();
queue.forEach((que) => {
showNotification(que)
})
}
}
// 톡방 내용 가져오기
const getMoreMessageLine = (talkId) => {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === talkId)[0];
cacheTalk.messageParams['insDate'] = cacheTalk.talkMessages.talks[cacheTalk.talkMessages.talks.length - 1].insDate;
return new Promise((resolve, reject) => {
global.request({
url: `/api/message/line`,
method: 'get',
params: cacheTalk.messageParams,
withCredentials: true
}).then((dto) => {
if (dto.talks.length > 0) {
messageMapping(talkId, dto, 'before', false);
talkEvent.messageScrollOriginalPositionMove();
let result = '';
if (cacheTalk.talkMessages.talks.length >= dto.total) {
result = 'last';
} else {
result = 'success';
}
HubEvent.send(global.talkParams({
type: 'MORE_MESSAGE_LINE',
talkId: talkId,
tabId: global.tabId,
result: result,
talkMessages: dto
}))
resolve(result)
} else {
resolve('last');
}
}).catch(function (error) {
reject(error)
})
})
}
// 톡방내 메시지 검색
const getMessageSearch = (params) => {
global.request({
url: `/api/message/search`,
method: 'get',
params: {talkId: params.talkId, search: params.search},
withCredentials: true
}).then((lists) => {
params.callback(lists)
})
}
// 메시지 통합 검색
const getAllContentSearch = (params) => {
global.request({
url: `/api/message/search/all`,
method: 'get',
params: {search: params.search},
withCredentials: true,
}).then((lists) => {
params.callback(lists)
})
}
//매뉴얼 조회
const getManual = (params) => {
const sendParam = {type: params.type}
if(params.search !== '') sendParam['search'] = params.search
if(params.workId !== '') sendParam['workId'] = params.workId
global.request({
url: `/api/manual`,
method: 'get',
params: sendParam,
withCredentials: true
}).then((manuals) => {
params.callback(manuals)
})
}
//매뉴얼 조회
const getVideoManual = (params) => {
const sendParam = {type: params.type}
if(params.search !== '') sendParam['search'] = params.search
if(params.workId !== '') sendParam['workId'] = params.workId
global.request({
url: `/api/manual/video`,
method: 'get',
params: sendParam,
withCredentials: true
}).then((manuals) => {
params.callback(manuals)
})
}
// 톡방 삭제 (실제 삭제 여부만 갱신)
const deleteTalk = (params) => {
global.request({
url: `/api/talk/delete/${params.talkId}`,
method: 'put',
withCredentials: true
}).then((data) => {
params.callback(data)
})
}
// 톡방 읽음 표시
const setChatRead = (talkId) => {
console.log('read', talkId)
return new Promise((resolve, reject) => {
global.request({
url: `/api/message/read`,
method: 'post',
body: {talkId: talkId},
withCredentials: true
}).then((result) => {
resolve(result);
}).catch((err) => {
reject(err);
})
})
}
// 톡방 보관
const setTalkMark = (obj) => {
global.request({
url: `/api/talk/mark/${obj.talkId}`,
method: 'put',
withCredentials: true
}).then(() => {
obj.callback()
})
}
export {
talkInit,
getUser,
getApInfo,
getTalkList,
getTalkListEvent,
setChatList,
getMessage,
getMoreMessageLine,
getMessageSearch,
getAllContentSearch,
getManual,
getVideoManual,
setChatRead,
setTalkMark,
setITSMSatis,
setSCMSatis,
deleteTalk,
getMessageAll,
getMoreMessageAll
}

View File

@@ -0,0 +1,201 @@
import {talkEvent} from "http://talk.kospo.co.kr:3000/static/js/module/talkEvent.js";
import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js";
import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js";
// 첨부파일 업로드 기능
function readFileAsDataURL(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
});
}
const attachUpload = async (files) => {
checkAllowExt()
const chunkSize = 256 * 1024;
const key = talkEvent.generateUUID()
const workId = localStorage.getItem('workId');
const workNm = localStorage.getItem('workNm');
const talkId = localStorage.getItem(global.tabId);
if(talkId === null || workId === null) {
global.notifier.alert('통신 오류가 발생 했어요.<br/>새로고침 해주세요.')
return
}
const $files = [];
const insDate = Common.dateWithNanos(new Date());
let allFileSize = 0;
let isImage = true;
// mimtype 조회 이미지가 아닌 다른 파일이 있는지 확인
Array.from(files).forEach((fi) => {
if (!(fi.type.includes('image'))) {
isImage = false;
}
})
for (const file of Array.from(files)) {
const idx = Array.from(files).indexOf(file);
allFileSize += file.size;
const att = {
onm: file.name,
type: file.type,
sort: idx,
size: file.size,
}
// 파일 전체가 이미지 일 경우 해당 바이너리 정보 주입
if (isImage) {
// 1. 파일을 읽어서 DataURL로 변환 (FileReader 비동기 처리)
const dataURL = await readFileAsDataURL(file);
// 2. 변환된 DataURL을 이용해 이미지 로드 (Image 비동기 처리)
const img = await loadImage(dataURL);
// 3. 썸네일 용 dataURL 생성
const blob = await Common.cropImage(img, 105);
att.data = blob;
}
$files.push(att);
}
/*
첨부파일 업로드 설정 소켓 통신으로 해당 파일의 정보를 보내준다.
정보를 받는 대상자는 첨부파일 업로드 화면을 렌더링 한다.
이미지 같은 경우는 위 바이너리 정보로 썸네일 구성
이미지외 파일 혼합된 경우 파일 다운로드 화면 구성
(서버에서는 해당 내용으로 메시지를 저장한다.)
*/
talkEvent.attach(global.talkParams({
type: 'INIT',
talkId: talkId,
workId: workId,
workNm: workNm,
message: isImage ? "[사진]" : '[파일]',
insDate: insDate,
talkAttachDtos: $files,
attach: {
key: key,
totalSize: allFileSize
}
}))
setTimeout(attachStart, 300)
function checkAllowExt() {
const allow = ["jpg", "jpeg", "gif", "png", "bmp",
"xls", "xlsx", "csv", "pdf", "hwp", "doc", "docx", "ppt", "pptx", "txt",
"zip", "egg",
"mp4"]
files = Array.from(files).filter((file) => {
const fileExt = file.name.toLowerCase().substr(file.name.toLowerCase().lastIndexOf('.') + 1)
return allow.join(',').includes(fileExt)
})
}
function attachStart() {
if (files.length !== 0) {
Array.from(files).forEach((file, idx) => {
const vnm = Common.getAttachVnm(new Date(), global.tabId)
console.log(idx, vnm)
let offset = 0;
/*
각파일 정보를 전송
(서버에서는 메시지 첨부파일을 저장한다.)
*/
talkEvent.attach(global.talkParams({
type: 'START',
talkId: talkId,
workId: workId,
workNm: workNm,
insDate: insDate,
attach: {
key: key,
onm: file.name,
vnm: vnm,
size: file.size,
type: file.type,
sort: idx,
totalSize: allFileSize
}
}))
readAndSEndChunk(file, idx, offset, vnm)
})
}
}
let progressSize = 0;
function readAndSEndChunk(file, idx, offset, vnm) {
const reader = new FileReader();
reader.onload = (e) => {
const chunk = reader.result;
/*
파일의 바이너리 정보를 chunkSize 256kb 로 잘라서 전송한다.
받는 대상자는 해당 첨부파일의 진행률을 돌려받는다.
*/
talkEvent.attach(global.talkParams({
type: 'PROGRESS',
talkId: talkId,
workId: workId,
workNm: workNm,
insDate: insDate,
attach: {
key: key,
onm: file.name,
sort: idx,
vnm: vnm,
totalSize: allFileSize,
size: progressSize,
data: Array.from(new Uint8Array(chunk))
},
}))
progressSize += chunk.byteLength;
offset += chunk.byteLength;
if (offset < file.size) {
Common.sleep(100).then(() => {
readAndSEndChunk(file, idx, offset, vnm)
})
} else {
/*
파일 전송 완료 메시지
*/
talkEvent.attach(global.talkParams({
type: 'END',
talkId: talkId,
workId: workId,
workNm: workNm,
insDate: insDate,
attach: {
onm: file.name,
vnm: vnm,
key: key,
},
}))
}
}
const slice = file.slice(offset, offset + chunkSize);
reader.readAsArrayBuffer(slice)
}
}
export {attachUpload}

View File

@@ -0,0 +1,229 @@
import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js";
import {HubEvent} from "http://talk.kospo.co.kr:3000/static/js/module/hubEvent.js";
import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js";
import {talkEvent} from "http://talk.kospo.co.kr:3000/static/js/module/talkEvent.js";
import {getMessageAll, getTalkList, getMoreMessageAll} from "http://talk.kospo.co.kr:3000/static/js/module/apis.js";
import receiver from "http://talk.kospo.co.kr:3000/static/js/module/receiver.js";
export default class Hub {
constructor() {
this.controller = new AbortController();
this.signal = this.controller.signal;
}
install() {
return new Promise(async (resolve, reject) => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(global.option.serviceWorkerLocation, {updateViaCache: 'none'})
.then(async registration => {
global.registration = registration;
let checker = true;
while (checker) {
if (global.registration.active !== undefined && global.registration.active !== null) checker = false;
await Common.sleep(5)
}
// 서비스워커 업데이트
registration.update();
// 서비스 워커 설치 완료후 HUB 소켓 연결 명령
HubEvent.connect({
type: 'CONNECT',
tabId: global.tabId,
url: global.apiUrl,
sabun: global.user.sabun,
encSabun: global.option.encSabun,
site: global.currentUrl
})
resolve();
})
.catch(error => {
console.error('Service Worker registration failed:', error);
reject();
});
}
})
}
// HUB 소켓 리시버 정의
start() {
console.log('hub message event start', new Date())
// navigator.serviceWorker.removeEventListener('message', this.message, {signal: this.controller.signal})
navigator.serviceWorker.addEventListener('message', this.message,{signal: this.signal})
}
stop() {
console.log('hub message event stop', new Date())
this.controller.abort();
this.controller = new AbortController();
this.signal = this.controller.signal;
}
message(event) {
const payload = event.data;
if(payload.type === 'PING') {
// console.log('PING', new Date())
try {
global.registration.active.postMessage({
type: 'PONG'
});
} catch(e) {}
} else if (payload.type === 'GETUP') {
global.serviceWorkerConnect = true;
} else if (payload.type === 'HUB_RECONNECT') {
HubEvent.close({
type: 'TAB_CLOSE',
tabId: global.tabId,
url: global.apiUrl,
sabun: global.user.sabun,
channelSabun: global.user.sabun,
site: global.currentUrl
})
global.hub.install().then(() => {
// global.hub.start();
HubEvent.start(global.talkParams({
type: 'START',
tabId: global.tabId
}))
// getMessageAll(false)
getMoreMessageAll()
global.registration.active.postMessage({'type': 'HUB_RECONNECT_SUCCESS'})
});
} else if (payload.type === 'SEND_OTHER_INIT') {
if (Common.isMaster()) {
HubEvent.otherInit({
type: 'OTHER_INIT',
talkData: global.talkData,
insSabun: global.user.sabun,
tabId: global.tabId
})
}
} else if (payload.type === 'SEND_SET_MASTER') {
if (!Common.isMaster()) {
global.init = false;
talkEvent.reConnect()
}
} else if (payload.type === 'SEND_TYPED') {
if (Common.isMaster()) {
payload.type = payload.type.replace('SEND_', '')
talkEvent.send(payload)
}
} else if (payload.type === 'OTHER_INIT') {
if (!Common.isMaster()) {
receiver.otherInit(payload)
}
} else if (payload.type === 'SEND') {
if (Common.isMaster()) {
talkEvent.send(payload)
}
} else if (payload.type === 'JOIN') {
receiver.join(payload)
} else if (payload.type === 'CHANGE') {
receiver.change(payload)
} else if (payload.type === 'START') {
receiver.start(payload)
} else if (payload.type === 'LEAVE') {
receiver.leave(payload)
} else if (payload.type === 'DELETE') {
receiver.delete(payload)
} else if (payload.type === 'WORK_ONLINE') {
receiver.workOnline(payload)
} else if (payload.type === 'WORK_OFFLINE') {
receiver.workOffline(payload)
} else if (payload.type === 'ONLINE') {
receiver.online(payload)
} else if (payload.type === 'OFFLINE') {
receiver.offline(payload)
} else if (payload.type === 'ERROR') {
receiver.error(payload)
} else if (payload.type === 'STATUS') {
receiver.message(payload)
} else if(payload.type === 'EXTERNAL_SAVE') {
receiver.externalSave(payload)
} else if (payload.type === 'INTRO') {
receiver.intro(payload)
} else if (payload.type === 'MESSAGE') {
global.checker.flag = false;
global.checker.inDate = '';
receiver.message(payload);
const chatContent = global.shadowRoot.querySelector('#chat-content');
const content = chatContent.querySelector('.simplebar-content');
const typedProgress = content.querySelector('.your-dot-progress');
if(typedProgress) {
const clone = typedProgress.cloneNode(true)
talkEvent.messageUnTyped()
content.insertAdjacentElement('beforeend', clone)
}
} else if(payload.type === 'QUESTION') {
receiver.message(payload);
} else if (payload.type === 'INFO_MESSAGE') {
receiver.infoMessage(payload)
} else if (payload.type === 'CLOSE') {
receiver.close(payload);
} else if (payload.type === 'TYPED') {
console.log('service worker message', payload)
receiver.typed(payload);
} else if (payload.type === 'UNTYPED') {
console.log('service worker message', payload)
receiver.untyped(payload);
} else if (payload.type === 'READ') {
receiver.read(payload);
} else if (payload.type === 'ATTACH_INIT') {
receiver.attachStart(payload);
} else if (payload.type === 'ATTACH_PROGRESS') {
receiver.attachProgress(payload);
} else if (payload.type === 'ATTACH_END') {
receiver.attachEnd(payload);
} else if (payload.type === 'MORE_MESSAGE_LINE') {
if (payload.tabId !== global.tabId) {
receiver.moreMessageLine(payload)
}
} else if (payload.type === 'DELETE') {
/*삭제처리*/
if (localStorage.getItem('talkId') === payload.talkId) {
const chatBack = global.shadowRoot.querySelector('.contacts-list-show');
chatBack.click();
}
talkEvent.talkRemove(payload.talkId)
} else if (payload.type === 'MARK') {
/*보관처리*/
talkEvent.talkMark(payload.talkId)
} else if (payload.type === 'UNSUBSCRIBE') {
/*새로운 탭 활성화시 현재 탭 외 모든 구독 해제 조건(탭아이디가 동일 하지 않으며 모든 로딩이 완료)*/
if (payload.tabId !== global.tabId && global.init) {
talkEvent.allUnsubscribe();
}
} else if (payload.type === 'WORK_COUNT') {
/*현재 업무 카운트*/
receiver.changeLoginInfo(payload)
} else if(payload.type === 'SW_RECONNECT') {
console.log('sw_reconnect')
// 개인 사번 소켓 연결
try{global.subscribeList[global.user.sabun] = talkEvent.userSubscribe();}catch(e){}
// 업무별 소켓 연결
try{global.subscribeList[global.work.workId] = talkEvent.workSubscribe();}catch(e){}
// 톡방 재갱신
// getMessageAll(false)
getMoreMessageAll()
if (Common.isMaster()) {
// 허브설정
HubEvent.start(global.talkParams({
type: 'START',
tabId: global.tabId
}))
// 현재 탭 외 모든 탭 구독 해지
HubEvent.send(global.talkParams({
type: 'UNSUBSCRIBE',
tabId: global.tabId
}))
}
} else if(payload.type === 'HEARTBEAT') {
console.log("PONG")
}
}
}

View File

@@ -0,0 +1,65 @@
import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js";
const HubEvent = {
start: (payload) => {
global.stomp.send(`/pub/hub.start.${global.tabId}`, {}, JSON.stringify(payload))
},
connect: (payload) => {
global.registration.active.postMessage(payload)
},
close: (payload) => {
if(payload.talkId === null) return false;
global.registration.active.postMessage(payload)
global.stomp.send(`/pub/hub.close.${global.tabId}`, {}, JSON.stringify(payload))
},
kill: (payload) => {
global.registration.active.postMessage(payload)
global.registration.unregister();
},
sendSetMaster: (payload) => {
payload.channelSabun = global.user.sabun
payload.tabId = global.tabId
global.stomp.send(`/pub/hub.send.setMaster`, {}, JSON.stringify(payload))
},
otherInit: (payload) => {
payload.channelSabun = global.user.sabun
payload.tabId = global.tabId
global.stomp.send(`/pub/hub.otherInit`, {}, JSON.stringify(payload))
},
send: (payload) => {
// console.log('hub send is me', payload)
if(payload.talkId === null) return false;
payload.channelSabun = global.user.sabun
payload.tabId = global.tabId
try {
if (payload.type === 'ONLINE' || payload.type === 'OFFLINE') {
global.stomp.send(`/pub/hub.online`, {}, JSON.stringify(payload))
} else if (payload.type === 'ATTACH_INIT') {
global.stomp.send(`/pub/hub.file.message`, {}, JSON.stringify(payload))
} else {
/*톡 요청 상태에 따른 comp_yn 완료 처리*/
if(payload.reqType === '9000') {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
cacheTalk.compYn= true
console.log(cacheTalk)
}
global.stomp.send(`/pub/hub.talk.message`, {}, JSON.stringify(payload))
}
} catch (e) {
}
},
fileSend: (payload) => {
if(payload.talkId === null) return false;
payload.channelSabun = global.user.sabun
payload.tabId = global.tabId
global.stomp.send(`/pub/hub.file.message`, {}, JSON.stringify(payload))
},
work: (payload) => {
payload.channelSabun = global.user.sabun
payload.tabId = global.tabId
global.stomp.send(`/pub/hub.work`, {}, JSON.stringify(payload))
}
}
export {HubEvent};

View File

@@ -0,0 +1,46 @@
import {global} from 'http://talk.kospo.co.kr:3000/static/js/module/variable.js';
import {talkEvent} from 'http://talk.kospo.co.kr:3000/static/js/module/talkEvent.js';
import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js";
class SocketQueue {
constructor() {
this.queue = [];
this.isSending = false;
}
enqueue(data) {
this.queue.push(data);
if(!this.isSending) {
this.processQueue();
}
}
async processQueue() {
this.isSending = true;
while(this.queue.length > 0) {
const data = this.queue.shift();
try {
await this.sendToSocket(data);
Common.sleep(30).then(() => {
this.isSending = false;
});
} catch(err) {
this.isSending = false;
console.error('전송실패', err)
}
}
}
async sendToSocket(data) {
return new Promise((resolve, reject) => {
if(global.sockJS.readyState === WebSocket.OPEN) {
talkEvent.send(global.talkParams(data));
resolve();
} else {
reject(new Error('소켓 연결 안됨'))
}
})
}
}
export default SocketQueue

View File

@@ -0,0 +1,657 @@
import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js";
import {infoMessage, systemMessage, talkMapping, messageMapping} from "http://talk.kospo.co.kr:3000/static/js/module/render.js";
import {getMessage, getTalkListEvent, setChatList, setChatRead} from "http://talk.kospo.co.kr:3000/static/js/module/apis.js";
import {showNotification} from 'http://talk.kospo.co.kr:3000/static/js/notification.js';
import {talkEvent} from "http://talk.kospo.co.kr:3000/static/js/module/talkEvent.js";
import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js";
import {HubEvent} from "http://talk.kospo.co.kr:3000/static/js/module/hubEvent.js"
// 소켓 메시지 이벤트
const receiver = {
workOnline: (payload) => {
const introOnline = global.shadowRoot.querySelector('#intro-online');
introOnline.classList.remove('offline');
introOnline.classList.add('online');
},
workOffline: (payload) => {
const introOnline = global.shadowRoot.querySelector('#intro-online');
introOnline.classList.remove('online');
introOnline.classList.add('offline');
},
online: (payload) => {
const onlineList = [];
if (payload.works.length === 0) {
const chatList = global.shadowRoot.querySelectorAll(`div[data-target-sabun="${payload.sabun}"]`)
chatList.forEach((el) => {
onlineList.push(el.dataset.talkId);
const offline = el.querySelector('.status-offline')
if (offline) {
offline.classList.remove('status-offline')
offline.classList.add('status-online')
}
})
} else {
const chatList = global.shadowRoot.querySelectorAll('.chat-wrap');
chatList.forEach((el) => {
// const targetSabun = el.getAttribute('data-target-sabun');
const smSabun = el.getAttribute('data-work-sm-sabun');
if (smSabun.includes(payload.sabun)) {
onlineList.push(el.dataset.talkId);
const offline = el.querySelector('.status-offline')
if (offline) {
offline.classList.remove('status-offline')
offline.classList.add('status-online')
}
}
})
}
global.talkData.forEach((talk) => {
if (onlineList.includes(talk.talkId)) {
talk.talkMembers.forEach((tm) => {
if (tm.sabun === payload.sabun) {
tm.onlineYn = true;
}
})
}
})
},
offline: (payload) => {
const offlineList = [];
let onlineYn = false;
if (payload.works.length === 0) {
const chatList = global.shadowRoot.querySelectorAll(`div[data-target-sabun="${payload.sabun}"]`)
chatList.forEach((el) => {
offlineList.push(el.dataset.talkId);
const offline = el.querySelector('.status-online')
if (offline) {
offline.classList.remove('status-online')
offline.classList.add('status-offline')
}
})
} else {
let oldtalkId = "";
const chatList = payload.talks.filter((ch) => {
if (ch.sabun !== global.user.sabun && ch.onlineYn) oldtalkId = ch.talkId;
if (ch.sabun !== global.user.sabun) return ch;
})
chatList.forEach((cl) => {
if (oldtalkId !== cl.talkId) {
const chatEl = global.shadowRoot.querySelector(`div[data-talk-id="${cl.talkId}"]`);
if (chatEl) {
const online = chatEl.querySelector('.status-online')
if (online) {
online.classList.remove('status-online')
online.classList.add('status-offline')
}
const smSabun = chatEl.getAttribute('data-work-sm-sabun');
if (smSabun.includes(payload.sabun)) {
offlineList.push(chatEl.dataset.talkId);
}
}
}
})
}
global.talkData.forEach((talk) => {
if (offlineList.includes(talk.talkId)) {
talk.talkMembers.forEach((tm) => {
if (tm.sabun === payload.sabun) {
tm.onlineYn = false;
}
})
}
})
},
error: (payload) => {
global.notifier.alert(payload.message)
},
join: (payload) => {
setChatList(payload)
if(localStorage.getItem(global.tab) === '' || localStorage.getItem(global.tab) === null ) {
if (!(payload.work.smUsers.map((sm) => sm.sabun).toString().indexOf(global.user.sabun) > -1)) {
// 방 생성자 주입
if (payload.tabId === global.tabId) {
/* 방 생성자 초기화 */
console.log("*(*******************A")
global.chatCreator = null;
talkEvent.messageShow();
localStorage.setItem(global.tabId, payload.talkId)
talkEvent.talkHeaderChange(payload.work.workNm, payload.work.smUsers.map((sm) => sm.name).join(','));
}
}
}
},
change: (payload) => {
setChatList(payload)
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
cacheTalk.messageParams = {};
cacheTalk.messageParams.talkId = payload.talkId;
cacheTalk.messageParams.start = 0;
cacheTalk.messageParams.row = 30;
cacheTalk.lastMessage = payload.lastMessage;
cacheTalk.lastMessageDate = payload.lastMessageDate;
cacheTalk.talkMessages = payload.talkMessages;
cacheTalk.talkMembers = payload.talkMembers
console.log('user change', cacheTalk)
if (!(payload.work.smUsers.map((sm) => sm.sabun).includes(global.user.sabun))) {
// 방 생성자 주입
if (payload.insSabun === global.user.sabun) {
const _this = global.shadowRoot.querySelector(`div[data-talk-id="${payload.talkId}"]`)
const talkId = _this.dataset.talkId;
const workId = _this.dataset.workId;
const workNm = _this.dataset.workNm;
const workSmNm = _this.dataset.workSmNm;
const currentTalkId = localStorage.getItem(global.tabId)
if (currentTalkId === payload.prevTalkId) {
talkEvent.talkHeaderChange(workNm, workSmNm)
global.talkClean();
global.scrollMoreFlag = false;
localStorage.setItem(global.tabId, talkId);
localStorage.setItem('workId', workId);
localStorage.setItem('workNm', workNm);
}
talkMapping(global.talkData)
}
}
},
start: (payload) => {
if(localStorage.getItem(global.tabId) === payload.talkId) {
if (global.user.sabun !== payload.insSabun) {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
cacheTalk.talkMembers = cacheTalk.talkMembers.filter((member) => (member.sabun === 'info' || member.sabun === global.user.sabun || member.sabun === payload.insSabun) )
// 앤드 유저 이벤트 설정
const room = global.shadowRoot.querySelector(`div[data-talk-id="${payload.talkId}"]`);
room.dataset.workSmNm = payload.insName
room.dataset.workSmSabun = payload.insSabun
talkEvent.talkTitleChange(payload.talkId, payload.insSabun)
talkEvent.talkHeaderChange(null, payload.insName)
} else {
// 유지보수 담당자 이벤트 설정
const room = global.shadowRoot.querySelector(`div[data-talk-id="${payload.talkId}"]`);
room.setAttribute("data-work-sm-nm", payload.insName)
room.setAttribute("data-work-sm-sabun", payload.insSabun)
talkEvent.talkHeaderChange(null, payload.insName)
}
}
},
leave: (payload) => {
/*구독 취소*/
talkEvent.talkRemove(payload.talkId);
if (Common.isMaster()) {
console.log('unsubscribe')
talkEvent.unsubscribe(payload.talkId);
}
if(localStorage.getItem(global.tabId) === payload.talkId) {
talkEvent.talkHeaderChange('', '')
global.reset()
}
},
delete: (payload) => {
/*구독 취소*/
talkEvent.talkRemove(payload.talkId);
if (Common.isMaster()) {
console.log('unsubscribe')
talkEvent.unsubscribe(payload.talkId);
}
},
close: (payload) => {
if (Common.isMaster()) {
talkEvent.unsubscribe(payload.talkId);
}
if (localStorage.getItem(global.tabId) === payload.talkId && !payload.force) {
global.element.chatEditorArea.classList.add('cus-hide');
const chatRatingConfirmWrapper = global.shadowRoot.querySelector('.chat-rating-confirm-wrapper')
chatRatingConfirmWrapper.classList.remove('cus-hide')
chatRatingConfirmWrapper.classList.add('cus-show')
}
const room = global.shadowRoot.querySelector(`div[data-talk-id="${payload.talkId}"]`);
/*상담 강제 종료시 만족사 조사 제외 완료 처리*/
if(payload.force) {
room.dataset.compYn = true;
room.dataset.ratingYn = true;
}
room.classList.add('chat-close');
const avatar = room.querySelector('.avatar')
avatar.classList.remove('status-online')
avatar.classList.remove('status-offline')
avatar.classList.add('status-do-not-disturb')
const roomData = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
roomData.closeYn = true;
talkMapping(global.talkData)
if(localStorage.getItem(global.tabId) === payload.talkId) {
global.element.chatEditorArea.classList.add('cus-hide');
}
},
intro: (payload) => {
if(localStorage.getItem(global.tabId) === payload.talkId) {
infoMessage(payload.message)
talkEvent.messageShow()
}
},
message: async (payload) => {
//기초 데이터 초기화
global.yourOldDate = '';
global.mineOldDate = '';
global.currDay = '';
let incrementIdxFlag = true;
let listening = 1;
// Common.setListening(1);
const master = Common.isMaster();
/*현재 톡방이 첨부파일 메시지 와 동일한 방이면 메시지 맵핑*/
if(master) {
if ((localStorage.getItem(global.tabId) === payload.talkId && document.visibilityState === 'hidden') || (localStorage.getItem(global.tabId) === payload.talkId && global.shadowRoot.querySelector('.chat-floating').classList.contains('cus-hide'))) {
listening = 3
} else if (localStorage.getItem(global.tabId) === payload.talkId) {
listening = 2
}
// 우선순위가 되는 상태 간격 조절
// Common.setListening(payload.talkId, listening);
} else {
listening = 99
// await Common.sleep(400)
}
/*메시지 호출이 안된 상태이면 제외 첫 접근도 안된 상태로 메시지 맵핑 필요없음*/
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
/* 메시지 존재 여부에 따른 분기 처리 */
try {
if (cacheTalk.talkMessages !== undefined) {
messageMapping(payload.talkId, {talks: [payload]}, 'after', false)
} else {
messageMapping(payload.talkId, {talks: [payload]}, 'after', true)
}
} catch(e) {
global.notifier.alert('통신 오류가 발생 했어요.<br/>새로고침 해주세요.')
return;
}
/*
톡방에 입장중이면 썸네일 메시지 전송
입장중이 아니면 톡방 목록에 배지 카운트 추가및 메시지 메시지 변경
* */
const msg = payload.message.includes('[매뉴얼]') ? '[매뉴얼]' : payload.message
// await Common.sleep(200)
// listening = Common.getListening(payload.talkId);
if (listening === 1) {
if(master) {
if (payload.type !== 'QUESTION') {
showNotification({
workNm: payload.workNm,
talkId: payload.talkId,
message: msg,
insName: payload.insName,
});
}
}
} else if(listening === 2 || listening === 3) {
// 메인탭만 작동하도록 조치
// 현재 톡방 에 입장중이며 해당 탭이 비활성화 인상태 일시 쿠키값 변경
// if (localStorage.getItem(global.tabId) === payload.talkId && !document.hasFocus()) {
// Common.setListening(payload.talkId, 1);
// }
if (master) {
talkEvent.readMessage(payload.talkId)
}
if (payload.insSabun !== global.user.sabun) {
if (master) {
setChatRead(payload.talkId)
}
// 기타 톡방으로 메시지 읽음 전송
console.log('read')
HubEvent.send(global.talkParams({
type: "READ",
talkId: payload.talkId,
insSabun: global.user.sabun
}))
}
// 스크롤 옵저버가 꺼져 있을시 메시지 팝업으로 활성화
if (!global.scrollObserveFlag && payload.talkId === localStorage.getItem(global.tabId) && payload.insSabun !== global.user.sabun) {
talkEvent.preMessageShow(msg)
}
if (listening === 3) {
if (master) {
if (payload.type !== 'QUESTION') {
showNotification({
workNm: payload.workNm,
talkId: payload.talkId,
message: msg ,
insName: payload.insName,
});
}
}
}
incrementIdxFlag = false;
} else {
incrementIdxFlag = false;
}
// 톡방 데이터 주입
global.talkData.forEach((talk, idx) => {
if (talk.talkId === payload.talkId) {
talk.unReadCnt = incrementIdxFlag ? talk.unReadCnt + 1 : 0;
if (payload.type !== 'QUESTION') {
talk.lastMessage = msg;
talk.lastMessageDate = payload.insDate;
}
}
})
// 톡방 재정의
talkMapping(global.talkData)
// 메인 배지 재정의
if (payload.type !== 'QUESTION') {
talkEvent.badgeChange()
}
},
infoMessage: (payload) => {
console.log('infoMessage')
if(localStorage.getItem(global.tabId) === payload.talkId) {
if (payload.insSabun === global.user.sabun) {
systemMessage(payload.message);
// showNotification(payload.workNm, payload.talkId, message)
}
}
},
externalSave: (payload) => {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
cacheTalk.reqId = payload.reqId;
},
typed: (payload) => {
const currentTalkId = localStorage.getItem(global.tabId)
if (currentTalkId === payload.talkId) {
if (payload.insSabun !== global.user.sabun) {
talkEvent.messageTyped(payload);
}
}
},
untyped: (payload) => {
const currentTalkId = localStorage.getItem(global.tabId)
if (currentTalkId === payload.talkId) {
if (payload.insSabun !== global.user.sabun) {
talkEvent.messageUnTyped(payload);
}
}
},
read: (payload) => {
if (payload.insSabun === global.user.sabun) {
talkEvent.readMessage(payload.talkId)
}
},
attachStart: async (payload) => {
// 마스터 와 그외 탭간의 간격 조절
// 파일소켓 구독
payload.talkAttachDtos.forEach((att) => {
att.uploading = payload.uploading;
})
talkEvent.fileSubscribe(payload);
await Common.sleep(200)
global.yourOldDate = '';
global.mineOldDate = '';
global.currDay = '';
let incrementIdxFlag = true;
let listening = 1;
let sleepSecond = 10
const master = Common.isMaster();
/*현재 톡방이 첨부파일 메시지 와 동일한 방이면 메시지 맵핑*/
if(master) {
if ((localStorage.getItem(global.tabId) === payload.talkId && document.visibilityState === 'hidden') || (localStorage.getItem(global.tabId) === payload.talkId && global.shadowRoot.querySelector('.chat-floating').classList.contains('cus-hide'))) {
listening = 3
} else if (localStorage.getItem(global.tabId) === payload.talkId) {
listening = 2
}
// 우선순위가 되는 상태 간격 조절
Common.setListening(payload.talkId, listening);
} else {
await Common.sleep(100)
}
/*메시지 호출이 안된 상태이면 제외 첫 접근도 안된 상태로 메시지 맵핑 필요없음*/
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
if (cacheTalk.talkMessages !== undefined) {
messageMapping(payload.talkId, {talks: [payload]}, 'after', false)
// if (localStorage.getItem(global.tabId) === payload.talkId) {
// const uploadWrap = global.shadowRoot.querySelector(`div[data-key="${payload.attach.key}"]`);
// const messageWrap = uploadWrap.querySelector('.chat-message');
// messageWrap.style.whiteSpace = 'nowrap';
//
// /* 다운로드 시작시 배경 페이드 활성화 */
// const imageFade = uploadWrap.querySelector('.file-fade')
// imageFade.classList.remove('cus-hide');
// /*다운로드 버튼 비활성화*/
// const downloadBtn = uploadWrap.querySelector('.chat-gallery-option')
// downloadBtn.classList.remove('cus-show')
// downloadBtn.classList.add('cus-hide')
// const chatFile = uploadWrap.querySelector('.chat-file')
// if (chatFile) {
// /*프로그레스 설정*/
// chatFile.insertAdjacentHTML('beforeend', `<div class="progress" style="margin-top:5px; margin-bottom:5px;">
// <div class="progress-bar bg-low-purple" role="progressbar" style="width:0%;" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">0%</div>
// </div>
// `)
// } else {
// messageWrap.insertAdjacentHTML('beforeend', `<div class="progress" style="margin-top:5px; margin-bottom:5px;">
// <div class="progress-bar bg-low-purple" role="progressbar" style="width:0%;" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">0%</div>
// </div>
// `)
// }
// }
}
/*
톡방에 입장중이면 썸네일 메시지 전송
입장중이 아니면 톡방 목록에 배지 카운트 추가및 메시지 메시지 변경
* */
listening = Common.getListening(payload.talkId);
if (listening === 1 || global.shadowRoot.querySelector('.chat-floating').classList.contains('cus-hide')) {
if (master) {
showNotification({
workNm: payload.workNm,
talkId: payload.talkId,
message: payload.message,
insName: payload.insName,
});
}
// if (global.user.sabun !== payload.insSabun) {
// const chatBadge = global.shadowRoot.querySelector('.unread.badge');
// // let badgeCount = chatBadge.innerText;
// // badgeCnt = parseInt(badgeCount) + 1;
// }
} else {
// 메인탭에서만 작동 하도록 조치
if (master) {
talkEvent.readMessage(payload.talkId)
}
// 기타 탭으로 메시지 읽음 전송
if (payload.insSabun !== global.user.sabun) {
if (master) {
setChatRead(payload.talkId)
}
HubEvent.send(global.talkParams({
type: "READ",
talkId: payload.talkId,
insSabun: global.user.sabun
}))
}
if (master && !document.hasFocus()) {
showNotification({
workNm: payload.workNm,
talkId: payload.talkId,
message: payload.message,
insName: payload.insName,
});
}
// 스크롤 옵저버가 꺼져 있을시 메시지 팝업으로 활성화
if (!global.scrollObserveFlag && payload.talkId === localStorage.getItem(global.tabId) && payload.insSabun !== global.user.sabun) {
talkEvent.preMessageShow(payload.message)
}
incrementIdxFlag = false;
}
// 톡방 정보에 정보 주입
global.talkData.forEach((talk, idx) => {
if (talk.talkId === payload.talkId) {
talk.unReadCnt = incrementIdxFlag ? talk.unReadCnt + 1 : 0;
talk.lastMessage = payload.message;
talk.lastMessageDate = payload.insDate;
global.talkData.splice(idx, 1)
global.talkData = [talk, ...global.talkData]
}
})
// 톡방 재정의
talkMapping(global.talkData)
// 메인 배지 재정의
talkEvent.badgeChange()
},
attachProgress: (payload) => {
if (localStorage.getItem(global.tabId) === payload.talkId) {
const uploadWrap = global.shadowRoot.querySelector(`div[data-ins-date="${payload.insDate}"]`);
const progressBar = uploadWrap.querySelector('.progress-bar')
if (progressBar) {
if(Number(progressBar.style.width.replace('%', '')) < Number(payload.attach.percent.replace('%', ''))) {
progressBar.style.width = payload.attach.percent;
progressBar.innerText = payload.attach.percent;
}
}
}
},
attachEnd: (payload) => {
/*파일 구독 삭제*/
if (Common.isMaster()) {
console.log('attachEnd : ' + JSON.stringify(global.fileSubscribeList[payload.talkId]))
global.fileSubscribeList[payload.talkId].unsubscribe()
delete global.fileSubscribeList[payload.talkId];
}
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
if (cacheTalk.talkMessages !== undefined) {
cacheTalk.talkMessages.talks.forEach((talks) => {
if(talks.insDate === payload.insDate) {
talks.talkAttachDtos.forEach((att) => {
att.uploading = false;
})
}
})
}
console.log(cacheTalk)
if (localStorage.getItem(global.tabId) === payload.talkId) {
messageMapping(payload.talkId, cacheTalk.talkMessages, 'before', true)
}
},
otherInit: (payload) => {
global.talkData = payload.talkData
console.log(global)
getTalkListEvent();
},
messageLine: (payload) => {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
cacheTalk.talkMessages = JSON.parse(payload.talkMessages);
cacheTalk.messageParams = JSON.parse(payload.messageParams)
console.log(`receiver MESSAGE_LINE : `, cacheTalk)
if (localStorage.getItem(global.tabId) === payload.talkId) {
console.log('messageMapping')
messageMapping(payload.talkId, cacheTalk.talkMessages, 'before', true)
if (cacheTalk.talkMessages.length !== cacheTalk.talkMessages.total) {
setTimeout(() => {
global.scrollMoreFlag = true;
}, 1000)
}
}
},
moreMessageLine: (payload) => {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === payload.talkId)[0];
cacheTalk.talkMessages.talks = [...payload.talkMessages.talks, ...cacheTalk.talkMessages.talks];
console.log(`receiver MORE_MESSAGE_LINE : `, cacheTalk)
if (localStorage.getItem(global.tabId) === payload.talkId) {
console.log('messageMapping', global.oldScrollPosition)
messageMapping(payload.talkId, cacheTalk.talkMessages, 'before', true)
talkEvent.messageScrollOriginalPositionMove();
if (payload.result === 'success') {
global.scrollMoreFlag = true;
} else if (payload.result === 'last') {
global.scrollMoreFlag = false;
}
}
},
talkRefresh: (payload) => {
global.talkData = JSON.parse(payload.talkData)
console.log('talkRefresh', global.talkData)
},
changeLoginInfo: (payload) => {
console.log('work_count', payload.notStart)
const introOnline = global.shadowRoot.querySelector('#intro-online')
if (payload.notStart < 5) {
introOnline.style.setProperty('--after-content', `'지금은 바로 답변 받으실 수 있어요'`);
introOnline.style.setProperty('--before-background', '#00d27a');
} else if (payload.notStart < 10) {
introOnline.style.setProperty('--after-content', `'현재 문의량이 많아 답변이 늦어져요. (대기시간 10분)'`);
introOnline.style.setProperty('--before-background', '#fd7e14');
} else if (payload.notStart >= 10) {
introOnline.style.setProperty('--after-content', `'현재 문의량이 많아 답변이 늦어져요. (대기시간 30분)'`);
introOnline.style.setProperty('--before-background', '#e63757');
}
}
}
export default receiver;

View File

@@ -0,0 +1,950 @@
import m from 'http://talk.kospo.co.kr:3000/static/bundle/mithril-2.2.2/mithril.js'
import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js";
import {talkEvent} from "http://talk.kospo.co.kr:3000/static/js/module/talkEvent.js"
import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js";
// 화면 랜더링 관련 기능
const talkMapping = (chats) => {
talkEvent.talkSort()
const vnode = [];
const chatList = global.shadowRoot.querySelector('#chat-list');
if(chats.length === 0) {
vnode.push(
m('img', {class: 'chat-empty', src: `http://talk.kospo.co.kr:3000/static/image/empty.svg?color=${global.option.button.color.replace("#", '')}`})
)
} else {
for (const ch of chats) {
let smName = []
let smSabun = []
let unRead = '';
let avatar = null;
let onlineYn = false;
/*문의자가 방은 만들었지만 메시지 작성이 없을시 제외*/
if((ch.lastMessage !== null && ch.lastMessage !== '') || !ch.work.smUsers.map((sm) => sm.sabun).join(',').includes(global.user.sabun)) {
ch.work.smUsers.forEach((sm) => {
ch.talkMembers.forEach((cm) => {
if(sm.sabun === cm.sabun) {
smName.push(sm.name);
smSabun.push(sm.sabun);
if(cm.onlineYn && global.user.sabun !== sm.sabun) {
onlineYn = true;
}
} else {
if(global.user.sabun === sm.sabun) {
if(cm.onlineYn && cm.sabun !== global.user.sabun) {
if(!onlineYn) {
onlineYn = cm.onlineYn
}
}
}
}
})
})
if (smName.length === 0 && smSabun.length === 0) {
ch.talkMembers.forEach((cm) => {
if (cm.sabun !== global.user.sabun) {
smName.push(cm.name);
smSabun.push(cm.sabun);
}
})
}
if(ch.unReadCnt !== 0) {
unRead = m('div', {class:'chat-list-badge bg-danger'}, ch.unReadCnt);
}
if(ch.work.workLogo === null) {
avatar = m('div', {class:`avatar avatar-xl ${ch.closeYn ? 'status-do-not-disturb' : (onlineYn ? 'status-online' : 'status-offline')}`}, [
m('div', {class:'rounded-square chat-room-avatar'}, ch.insSabun === global.user.sabun ? `${ch.work.workNm.substring(0, 1)}` : ch.insName.substring(0, 1))
])
} else {
avatar = m('div', {class:`avatar avatar-xl ${ch.closeYn ? 'status-do-not-disturb' : (onlineYn ? 'status-online' : 'status-offline')}`}, [
m('img', {src: `${global.apiUrl}/logo/${ch.work.workLogo.vnm}`, class:`avatar avatar-xl ${ch.closeYn ? 'status-do-not-disturb' : (onlineYn ? 'status-online' : 'status-offline')}`})
])
}
vnode.push(m('div', {class:`cus-show hover-actions-trigger chat-wrap nav-item ${ch.unReadCnt === 0 ? '' : 'unread-message'} ${ch.closeYn ? 'chat-close' : ''}`, role:"tab", 'data-bs-toggle':"tab", 'data-bs-target':"#chat-0", 'aria-controls':"chat-0",
'aria-selected':"true", 'data-work-id':`${ch.work.workId}`, 'data-work-nm':`${ch.work.workNm}`, 'data-target-sabun': `${ch.insSabun}`, 'data-work-sm-nm':`${smName.join(',')}`, 'data-work-sm-sabun' : `${smSabun.join(',')}`, 'data-talk-id':`${ch.talkId}`, 'data-comp-yn':`${ch.compYn}`, 'data-close-yn':`${ch.closeYn}`, 'data-rating-Yn':`${ch.ratingYn}`}, [
m('div', {class:"d-lg-block"}, [
m('div', {class:"dropdown dropdown-active-trigger dropdown-chat"}, [
m('button', {class:"bg-transparent chat-options hover-actions btn btn-link btn-sm text-400 dropdown-caret-none dropdown-toggle end-0 fs-9 mt-3 me-1 z-1 pb-2 mb-n2", type:"button", 'data-boundary':"viewport",'data-bs-auto-close': 'true', 'data-bs-toggle':"dropdown", 'aria-haspopup':'true', 'aria-expanded':'false'}, [
m('i', {class: 'bi bi-gear-fill bi-color-grey'})
]),
m('div', {class:'dropdown-menu dropdown-menu-end border py-2 rounded-3'}, [
m('button', {class:'dropdown-item chat-mark bg-transparent'}, '보관'),
m('div', {class:'dropdown-divider'}),
m('button', {class:'dropdown-item chat-delete text-danger bg-transparent'}, '삭제')
])
])
]),
m('div', {class:'d-flex p-3', role:'button'}, [
avatar,
m('div', {class:'flex-1 chat-wrap-body ms-3 d-lg-block'}, [
m('div', {class: 'd-flex justify-content-between', style:'padding-bottom:3px;'}, [
m('h6', {class:`mb-0 chat-wrap-title ${smName.length === 1 ? '': 'cus-tooltip'} ${ch.markYn ? 'pin': ''}`, 'data-tooltip':`${smName.join(',')}`}, global.user.sabun === ch.insSabun ? `${ch.work.workNm} (${smName.length === 1 ? smName[0] : smName[0]+'외 '+ (smName.length -1)+'명'})` : `${ch.insName}(${ch.insSabun})`),
m('span', {class:'message-time'}, Common.talkListDateFormat(ch.lastMessageDate))
]),
m('div', {class:'min-w-0 max-h-15'}, [
m('div', {class:'chat-wrap-content pe-3'}, Common.nullCheck(ch.lastMessage)),
m('div', {class:'position-absolute bottom-0 end-0 hover-hide'}),
unRead
])
])
]),
]));
}
}
}
m.render(chatList, []);
m.render(chatList, vnode);
}
/*정보메시지 전송*/
const infoMessage = (msg) => {
return m('div', {class: 'd-flex p-2 pb-3 chat-info'}, [
m('div', {class:'flex-1 px-3'}, [
m('div', {class:'v-100'}, [
m('div', {class: 'hover-actions-trigger'}, [
m('div', {class:'bg-info text-white p-2 rounded-3 w-100 text-center text-pre-wrap', 'data-bs-theme': 'light'}, msg)
])
])
])
])
}
const systemMessage = (msg) => {
const html = [];
html.push(`<div class="d-flex p-2 pb-3 system-message">`);
html.push(`<div class="flex-1 px-3">`)
html.push(`<div class="v-100">`)
html.push(`<div class="hover-actions-trigger">`)
html.push(`<div class="bg-info text-white p-2 rounded-2 w-100 text-center text-pre-wrap" data-bs-theme="light">`)
html.push(msg);
html.push(`</div>`);
html.push(`</div>`);
html.push(`</div>`);
html.push(`</div>`);
html.push(`</div>`);
const chatContent = global.shadowRoot.querySelector('#chat-content');
const content = chatContent.querySelector('.simplebar-content');
content.insertAdjacentHTML('beforeend', html.join(''))
}
/*채팅 날짜 엘리먼트 생성*/
const dateMessage = (date) => {
return m('div', {class: 'text-center fs-10 text-500 chat-content-date p-2'}, [
m('span', date)
])
}
/*이미지 미리보기 */
const setImageModal = (param) => {
console.log(1)
const cca = JSON.parse(param);
// global.shadowRoot.querySelector('.modal-title').innerText = decodeURI(cca.onm)
const modalBody = global.shadowRoot.querySelector('.modal-body');
const img = m('img', {'src': `${global.apiUrl}/api/message/image?${new URLSearchParams(cca)}`, class: 'w-100'})
m.render(modalBody, img)
}
const messageMapping = (talkId, dto, position, reset) => {
let prevTalkId = '';
let vNode = []
global.currDay = '';
const chatContent = global.shadowRoot.querySelector('#chat-content');
const content = chatContent.querySelector('.simplebar-content');
const cacheTalk = global.talkData.filter((talk) => talk.talkId === talkId)[0];
// 톡방 메시지가 존재 하지 않을시 강제 주입
if(cacheTalk.talkMessages.talks === undefined || cacheTalk.talkMessages.talks === null) {
cacheTalk.talkMessages = dto;
} else {
if(reset) {
cacheTalk.talkMessages = dto;
} else {
if(position === 'after') cacheTalk.talkMessages.talks = [...cacheTalk.talkMessages.talks, ...dto.talks];
else if(position === 'before') cacheTalk.talkMessages.talks = [...dto.talks, ...cacheTalk.talkMessages.talks];
cacheTalk.talkMessages.total = cacheTalk.talkMessages.total + dto.talks.length;
}
}
if(localStorage.getItem(global.tabId) === talkId) {
for (const idx in cacheTalk.talkMessages.talks) {
try {
const msg = cacheTalk.talkMessages.talks[idx];
const nextMsg = cacheTalk.talkMessages.talks[parseInt(idx) +1];
const newDate = Common.dayOfWeek(msg.insDate.substring(0, 10));
if (global.currDay !== newDate) {
vNode.push(...[dateMessage(newDate)])
global.currDay = newDate
}
const chatDate = Common.talkDateFormat(msg.insDate);
let nextDate = nextMsg === undefined ? '' : (nextMsg.insSabun === 'info' ? "" : Common.talkDateFormat(nextMsg.insDate));
if(msg.insSabun === 'info') {
vNode.push(...[infoMessage(msg.message)])
} else if (global.user.sabun === msg.insSabun) {
/*이전 대화내용이 본인이 아니고 채팅 날짜 일때는 강제 입력 날짜 주입*/
let force = false;
try {
force = (vNode[vNode.length - 1].attrs.className.includes('your') ||
vNode[vNode.length - 1].attrs.className.includes('chat-content-date') ||
vNode[vNode.length - 1].attrs.className.includes('chat-info')) && !nextMsg;
if(!force) {
force = global.user.sabun !== (nextMsg === undefined ? '' : nextMsg.insSabun);
}
} catch(e) {
force = true;
}
vNode.push(...mineMessage(msg, chatDate, nextDate, force))
} else {
/*이전 대화내용이 본인이 아니고 채팅 날짜 일때는 강제 입력 날짜 주입*/
let force = false;
try {
/*다음 메시지가 존재 하지 않으면 이전 글이 상대발 글일시 날짜 주입*/
force = (vNode[vNode.length - 1].attrs.className.includes('mine') ||
vNode[vNode.length - 1].attrs.className.includes('chat-content-date') ||
vNode[vNode.length - 1].attrs.className.includes('chat-info')) && !nextMsg;
if(!force) {
force = global.user.sabun === (nextMsg === undefined ? '' : nextMsg.insSabun);
}
} catch(e) {
force = true;
}
vNode.push(...yourMessage(msg, vNode[vNode.length - 1], chatDate, nextDate, force))
}
prevTalkId = msg.talkId;
} catch(e) {
}
}
m.render(content, vNode)
}
}
const mineFileMessage = (msg, date, nextDate, force) => {
const talkAttachDtos = msg.talkAttachDtos;
const key = msg.attach == null ? '' : msg.attach.key;
let downloadFlag = true;
const downloadParam = {
talkId : msg.talkId,
sabun : msg.insSabun,
insDate : msg.insDate,
}
let delYn = false;
let onm = '';
let size = 0;
let fileIcon = '';
talkAttachDtos.forEach((cc) => {
size = size + cc.size
if(cc.delYn) delYn = true;
if(cc.uploading) downloadFlag = false;
});
if(talkAttachDtos.length === 1) {
fileIcon = 'bi-file-earmark-text'
onm = talkAttachDtos[0].onm;
} else {
fileIcon = 'bi-file-earmark-zip'
onm = `${talkAttachDtos[0].onm}${talkAttachDtos.length - 1}.zip`;
}
size = Math.round(size / 1024);
let tailFlag = false;
let insDate;
if(force) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
} else {
if(date !== nextDate) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
}
}
if(global.mineOldDate !== date) {
tailFlag = true;
global.mineOldDate = date
}
return m('div', {class: 'd-flex p-1 chat-text-wrapper mine cus-show', 'data-key': key, 'data-ins-date' : msg.insDate}, [
m('div', {class: 'flex-1 d-flex justify-content-end'}, [
m('div', {class: 'w-max-85'}, [
m('div', {class: 'hover-actions-trigger d-flex flex-end-center'}, [
m('ul', {class: 'position-relative list-inline mb-0 text-400 me-2 chat-gallery-option mr-10'}, [
delYn ? '' :
m('li', {class: 'list-inline-item'}, [
downloadFlag ?
m('a', {
class: 'chat-option',
href: `${global.apiUrl}/api/message/download?${new URLSearchParams(downloadParam).toString()}`,
target: '_download_',
rel: 'noopener',
'ata-bs-toggle': "tooltip",
'data-bs-placement': "top",
'aria-label': "Forward",
'data-bs-original-title': "Forward"
}, [
m('i', {class: 'bi bi-download text-black', style: 'font-size: 12px;'})
]) : ''
])
]),
m('div', {'search-yn': `${msg.searchYn}`, class: `chat-content-custom-font-size chat-message bg-light p-2 rounded-3 mr-10 chat-file ${tailFlag ? 'tail': ''}`, style: 'max-width:250px;'}, [
delYn ? m('div', {class: 'attach-del'}) : '',
m('div', {class: 'file-fade cus-hide'}),
m('div', {class: 'd-flex justify-content-between'}, [
m('div', {}, [
m('i', {class: `bi ${fileIcon}`, style: 'color:#505050;font-size:30px;padding-right:10px;'}),
]),
m('div', {class: 'attach-file'}, [
m('div', {class: 'fs-xxl-10 pb-1 attach-file'}, onm),
m('div', {class: 'fs-xxl-11'},`용량 : ${size}kb`),
])
]),
downloadFlag ? '': m('div', {class: 'progress', style: 'margin-top:5px; margin-bottom:5px;'}, [
m('div', {class:'progress-bar bg-low-purple', role: 'progressbar', style: 'width:0%;', 'aria-valuenow': "100",'aria-valuemin':"0", 'aria-valuemax':"100" }, '0%')
])
]),
]),
insDate
])
])
])
}
const mineManualMessage = (msg, date, manualParam, nextDate, force) => {
const downloadParam = {
vnm : manualParam.vnm,
workId : manualParam.workId,
}
const fileIcon = 'bi-file-earmark-text'
const size = Math.round(parseInt(manualParam.size) / 1024);
let tailFlag = false;
let insDate;
if(force) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
} else {
if(date !== nextDate) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
}
}
if(global.mineOldDate !== date) {
tailFlag = true;
global.mineOldDate = date
}
return m('div', {class: 'd-flex p-1 chat-text-wrapper mine cus-show'}, [
m('div', {class: 'flex-1 d-flex justify-content-end'}, [
m('div', {class: 'w-max-85'}, [
m('div', {class: 'hover-actions-trigger d-flex flex-end-center'}, [
m('ul', {class: 'position-relative list-inline mb-0 text-400 me-2 chat-gallery-option mr-10'}, [
m('li', {class: 'list-inline-item'}, [
m('a', {
class: 'chat-option',
href: `${global.apiUrl}/api/manual/download/doc?${new URLSearchParams(downloadParam).toString()}`,
target: '_download_',
rel: 'noopener',
'ata-bs-toggle': "tooltip",
'data-bs-placement': "top",
'aria-label': "Forward",
'data-bs-original-title': "Forward"
}, [
m('i', {class: 'bi bi-download text-black', style: 'font-size: 12px;'})
])
])
]),
m('div', {'search-yn': `${msg.searchYn}`, class: `chat-content-custom-font-size chat-message bg-light p-2 rounded-3 mr-10 chat-file ${tailFlag ? 'tail': ''}`, style: 'max-width:250px;'}, [
m('div', {class: 'file-fade cus-hide'}),
m('div', {class: 'd-flex justify-content-between'}, [
m('div', {}, [
m('i', {class: `bi ${fileIcon}`, style: 'color:#505050;font-size:30px;padding-right:10px;'}),
]),
m('div', {class: 'attach-file'}, [
m('div', {class: 'fs-xxl-10 pb-1 attach-file'}, manualParam.onm),
m('div', {class: 'fs-xxl-11'},`용량 : ${size}kb`),
])
])
]),
]),
insDate
])
])
])
}
/*자신에게 보이는 첨부파일 메시지 정의*/
const mineImageMessage = (msg, date, nextDate, force) => {
const talkAttachDtos = msg.talkAttachDtos;
const key = msg.attach == null ? '' : msg.attach.key;
let downloadFlag = true;
let attachList = []
let delYn = false
talkAttachDtos.forEach((cca, idx) => {
if(cca.uploading) downloadFlag = false;
if(cca.delYn) delYn = true;
const imageParam = {
talkId : msg.talkId,
sabun : msg.insSabun,
insDate : msg.insDate,
onm : encodeURI(cca.onm),
sort : cca.sort,
size : 100
}
const jsonStr = JSON.stringify(imageParam)
const remain = talkAttachDtos.length % 3
attachList.push(m('div', {onclick:function() {setImageModal(jsonStr)}, class:`col-${talkAttachDtos.length - remain > idx ? '4' : remain === 1 ? '12' : '6'} p-1`}, [
m('div', {'data-bs-toggle':"modal", 'data-bs-target':"#imageModal", 'data-url' :new URLSearchParams(imageParam).toString(), class:'attach-a'}, [
delYn ?
m('img', {src: `http://devtalk.kospo.co.kr:3000/static/image/empty_img.png`, alt: '', class: 'img-fluid rounded attach-img mb-2'}) :
m('img', {src: cca.data === null ? `${global.apiUrl}/api/message/thumb?${new URLSearchParams(imageParam).toString()}` : cca.data, alt: '', class: 'img-fluid rounded attach-img mb-2'})
])
]
))
})
const downloadParam = {
talkId : msg.talkId,
sabun : msg.insSabun,
insDate : msg.insDate,
}
/*
tail bg-primary text-white p-2 rounded-3 chat-message mr-10 mine
* */
let tailFlag = false;
let insDate;
if(force) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
} else {
if(date !== nextDate) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
}
}
if(global.mineOldDate !== date) {
tailFlag = true;
global.mineOldDate = date
}
return m('div', {class: 'd-flex p-1 chat-text-wrapper mine cus-show', 'data-key': key, 'data-ins-date' : msg.insDate}, [
m('div', {class: 'flex-1 d-flex justify-content-end'}, [
m('div', {class: 'w-xxl-85'}, [
m('div', {class: 'hover-actions-trigger d-flex flex-end-center'}, [
delYn ? '' :
m('ul', {class: 'position-relative list-inline mb-0 text-400 me-2 chat-gallery-option mr-10'}, [
m('li', {class: 'list-inline-item'}, [
downloadFlag ?
m('a', {
class: 'chat-option',
href: `${global.apiUrl}/api/message/download?${new URLSearchParams(downloadParam).toString()}`,
target: '_download_',
rel: 'noopener',
'ata-bs-toggle': "tooltip",
'data-bs-placement': "top",
'aria-label': "Forward",
'data-bs-original-title': "Forward"
}, [
m('i', {class: 'bi bi-download text-black', style: 'font-size: 14px;'})
]) : ''
])
]),
m('div', {'search-yn': `${msg.searchYn}`, class: `chat-content-custom-font-size bg-primary text-white p-2 rounded-3 chat-message mr-10 mine chat-gallery ${tailFlag ? 'tail': ''}`}, [
delYn ? m('div', {class: 'attach-del'}) : '',
m('div', {class: 'file-fade cus-hide'}),
m('div', {class: 'row mx-n1'}, attachList),
downloadFlag ? '': m('div', {class: 'progress', style: 'margin-top:5px; margin-bottom:5px;'}, [
m('div', {class:'progress-bar bg-low-purple', role: 'progressbar', style: 'width:0%;', 'aria-valuenow': "100",'aria-valuemin':"0", 'aria-valuemax':"100" }, '0%')
])
])
])
,insDate
])
])
]);
}
/*자신에게 보이는 메시지 정의*/
const mineMessage = (msg, date, nextDate, force) => {
const wrapper = global.shadowRoot.querySelectorAll('.chat-text-wrapper');
let merge = [];
let attaches;
let insDate;
let tailFlag = false;
/*첨부파일 리스트가 없을시 강제 리스트 주입*/
if(msg.talkAttachDtos === null || msg.talkAttachDtos === undefined) msg.talkAttachDtos = [];
/**/
if(msg.message.includes('[매뉴얼]')) {
const manualParam = JSON.parse(msg.message);
return mineManualMessage(msg, date, manualParam, nextDate, force)
} else if(msg.talkAttachDtos.length > 0) {
let isImage = true;
msg.talkAttachDtos.forEach((cca) => {
if(!(cca.type.includes('image'))) {
isImage = false;
}
})
if(isImage) {
attaches = mineImageMessage(msg, date, nextDate, force)
} else {
attaches = mineFileMessage(msg, date, nextDate, force)
}
merge = [
attaches,
];
} else {
if(force) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
} else {
if(date !== nextDate) {
insDate = m('div', {class: 'text-400 fs-11 chat-date text-end mr-10'}, [
m('span', `${date}`)
])
}
}
if(global.mineOldDate !== date) {
tailFlag = true;
global.mineOldDate = date;
}
let message = msg.message
let linkYn = false;
const urlRegex = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/g
const matches = message.match(urlRegex)
if(matches !== null) linkYn = true;
if(linkYn) {
if(message.includes('[ITSM]') || message.includes('[SCM]')) {
message = m.trust(message.replace(matches[matches.length -1], `<div class="detail-wrapper"><div class="detail-btn btn-sm btn-info btn-color" data-href="${matches[matches.length -1]}">자세히보기</div></div>`));
} else {
message = m.trust(message.replace(matches[matches.length -1], `<a title="${matches[matches.length -1]}" class="text-ellipsis" target="_blank" href="${matches[matches.length -1]}">${matches[matches.length -1]}</a>`));
}
}
merge = [
m('div', {class:'d-flex p-1 chat-text-wrapper mine cus-show'}, [
m('div', {class: 'flex-1 d-flex justify-content-end'}, [
m('div', {class: 'w-100'}, [
m('div', {class: 'hover-actions-trigger d-flex flex-end-center'}, [
m('div', {"data-line": `${msg.line}`, 'search-yn': `${msg.searchYn}`,class:`${tailFlag ? 'tail': '' } chat-content-custom-font-size bg-primary text-white p-2 rounded-3 chat-message mr-10 mine`, 'data-bs-theme':"light"}, message)
])
,insDate
])
])
])
];
}
return merge
}
const yourFileMessage = (msg, prevMsg, avatar, date, nextDate, force) => {
const talkAttachDtos = msg.talkAttachDtos;
const key = msg.attach == null ? '' : msg.attach.key;
let downloadFlag = true;
const downloadParam = {
talkId : msg.talkId,
sabun : msg.insSabun,
insDate : msg.insDate
}
let onm = '';
let size = 0;
let fileIcon = '';
let delYn = false;
talkAttachDtos.forEach((cc) => {
size = size + cc.size
if(cc.delYn) delYn = true;
if(cc.uploading) downloadFlag = false;
});
if(talkAttachDtos.length === 1) {
fileIcon = 'bi-file-earmark-text'
onm = talkAttachDtos[0].onm;
} else {
fileIcon = 'bi-file-earmark-zip'
onm = `${talkAttachDtos[0].onm}${talkAttachDtos.length - 1}.zip`;
talkAttachDtos.forEach((cc) => size = size + cc.size);
}
size = Math.round(size / 1024);
let insAvatar;
let insDate;
let tailFlag = false;
if(force) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
} else {
if(date !== nextDate) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
}
}
if(global.yourOldDate !== date || prevMsg.attrs.className.includes('mine')) {
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
tailFlag = true;
global.yourOldDate = date
}
return m('div', {class: 'd-flex p-1 chat-text-wrapper your cus-show', 'data-key': key, 'data-ins-date' : msg.insDate}, [
m('div', {class: 'avatar avatar-l me-2'}, [
insAvatar
]),
m('div', {class: 'flex-1 d-flex justify-content-start'}, [
m('div', {class: 'w-max-85'}, [
m('div', {class: 'hover-actions-trigger d-flex flex-between-normal'}, [
m('div', {'search-yn': `${msg.searchYn}`, class: `chat-content-custom-font-size chat-message bg-light p-2 rounded-3 ml-10 your chat-file ${tailFlag ? 'tail': ''}`, style: 'max-width:220px;'}, [
delYn ? m('div', {class: 'attach-del'}) : '',
m('div', {class: 'file-fade cus-hide'}),
m('div', {class: 'd-flex justify-content-start'}, [
m('i', {class: `bi ${fileIcon}`, style: 'color:#505050;font-size:30px;padding-right:10px;'}),
m('div', {class: ' attach-file'}, [
m('div', {class: 'fs-xxl-10 pb-1 attach-file'}, onm),
m('div', {class: 'fs-xxl-11'},`용량 : ${size}kb`),
])
]),
downloadFlag ? '': m('div', {class: 'progress', style: 'margin-top:5px; margin-bottom:5px;'}, [
m('div', {class:'progress-bar bg-low-purple', role: 'progressbar', style: 'width:0%;', 'aria-valuenow': "100",'aria-valuemin':"0", 'aria-valuemax':"100" }, '0%')
])
]),
delYn ? '' :
m('ul', {class: 'position-relative list-inline mb-0 text-400 me-2 chat-gallery-option ml-10'}, [
m('li', {class: 'list-inline-item'}, [
downloadFlag ?
m('a', {
class: 'chat-option',
href: `${global.apiUrl}/api/message/download?${new URLSearchParams(downloadParam).toString()}`,
target: '_download_',
rel: 'noopener',
'ata-bs-toggle': "tooltip",
'data-bs-placement': "top",
'aria-label': "Forward",
'data-bs-original-title': "Forward"
}, [
m('i', {class: 'bi bi-download text-black', style: 'font-size: 14px;'})
]): ''
]),
]),
]),
insDate
])
])
])
}
const yourManualMessage = (msg, prevMsg, manualParam, avatar, date, nextDate, force) => {
const downloadParam = {
vnm : manualParam.vnm,
workId : manualParam.workId,
}
const fileIcon = 'bi-file-earmark-text'
const size = Math.round(parseInt(manualParam.size) / 1024);
let insAvatar;
let insDate;
let tailFlag = false;
if(force) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
} else {
if(date !== nextDate) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
}
}
if(global.yourOldDate !== date || prevMsg.attrs.className.includes('mine')) {
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
tailFlag = true;
global.yourOldDate = date
}
return m('div', {class: 'd-flex p-1 chat-text-wrapper your cus-show'}, [
m('div', {class: 'avatar avatar-l me-2'}, [
insAvatar
]),
m('div', {class: 'flex-1 d-flex justify-content-start'}, [
m('div', {class: 'w-max-85'}, [
m('div', {class: 'hover-actions-trigger d-flex flex-between-normal'}, [
m('div', {'search-yn': `${msg.searchYn}`, class: `chat-content-custom-font-size chat-message bg-light p-2 rounded-3 ml-10 your chat-file ${tailFlag ? 'tail': ''}`, style: 'max-width:220px;'}, [
m('div', {class: 'file-fade cus-hide'}),
m('div', {class: 'd-flex justify-content-start'}, [
m('i', {class: `bi ${fileIcon}`, style: 'color:#505050;font-size:30px;padding-right:10px;'}),
m('div', {class: ' attach-file'}, [
m('div', {class: 'fs-xxl-10 pb-1 attach-file'}, manualParam.onm),
m('div', {class: 'fs-xxl-11'},`용량 : ${size}kb`),
])
])
]),
m('ul', {class: 'position-relative list-inline mb-0 text-400 me-2 chat-gallery-option ml-10'}, [
m('li', {class: 'list-inline-item'}, [
m('a', {
class: 'chat-option',
href: `${global.apiUrl}/api/manual/download/doc?${new URLSearchParams(downloadParam).toString()}`,
target: '_download_',
rel: 'noopener',
'ata-bs-toggle': "tooltip",
'data-bs-placement': "top",
'aria-label': "Forward",
'data-bs-original-title': "Forward"
}, [
m('i', {class: 'bi bi-download text-black', style: 'font-size: 14px;'})
])
])
]),
]),
insDate
])
])
])
}
/*상대방에게 보이는 첨부파일 메시지 정의*/
const yourImageMessage = (msg, prevMsg, avatar, date, nextDate, force) => {
let attachList = []
const talkAttachDtos = msg.talkAttachDtos;
let downloadFlag = true;
let delYn = false;
const key = msg.attach == null ? '' : msg.attach.key;
talkAttachDtos.forEach((cca, idx) => {
if(cca.uploading) downloadFlag = false;
if(cca.delYn) delYn = true;
const imageParam = {
talkId : msg.talkId,
sabun : msg.insSabun,
insDate : msg.insDate,
onm : encodeURI(cca.onm),
sort : cca.sort,
size : 100
}
const jsonStr = JSON.stringify(imageParam)
const remain = talkAttachDtos.length % 3
attachList.push(m('div', {onclick:function() {setImageModal(jsonStr)}, class:`col-${talkAttachDtos.length - remain > idx ? '4' : remain === 1 ? '12' : '6'} p-1`}, [
m('div', {'data-bs-toggle':"modal", 'data-bs-target':"#imageModal", 'data-url' :new URLSearchParams(imageParam).toString(), class:'attach-a'}, [
delYn ?
m('img', {src: `http://devtalk.kospo.co.kr:3000/static/image/empty_img.png`, alt: '', class: 'img-fluid rounded attach-img mb-2'}) :
m('img', {src: cca.data === null ? `${global.apiUrl}/api/message/thumb?${new URLSearchParams(imageParam).toString()}` : cca.data, alt: '', class: 'img-fluid attach-img rounded mb-2'})
])
]
))
return attachList;
})
const downloadParam = {
talkId : talkAttachDtos[0].talkId,
sabun : talkAttachDtos[0].sabun,
insDate : talkAttachDtos[0].insDate,
}
let insAvatar;
let insDate;
let tailFlag = false;
if(force) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
} else {
if(date !== nextDate) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
}
}
if(global.yourOldDate !== date || prevMsg.attrs.className.includes('mine')) {
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
tailFlag = true;
global.yourOldDate = date
}
return m('div', {class: 'd-flex p-1 chat-text-wrapper your cus-show', 'data-key': key, 'data-ins-date' : msg.insDate}, [
m('div', {class: 'avatar avatar-l me-2'}, [
insAvatar
]),
m('div', {class: 'flex-1 d-flex justify-content-start'}, [
m('div', {class: 'w-xxl-85'}, [
m('div', {class: 'hover-actions-trigger d-flex flex-between-normal'}, [
m('div', { 'search-yn': `${msg.searchYn}`,class: `chat-content-custom-font-size chat-message bg-200 p-2 rounded-3 ml-10 your chat-gallery ${tailFlag ? 'tail' : ''}`}, [
delYn ? m('div', {class: 'attach-del'}) : '',
m('div', {class: 'file-fade cus-hide'}),
m('div', {class: 'row mx-n1'}, attachList),
downloadFlag ? '': m('div', {class: 'progress', style: 'margin-top:5px; margin-bottom:5px;'}, [
m('div', {class:'progress-bar bg-low-purple', role: 'progressbar', style: 'width:0%;', 'aria-valuenow': "100",'aria-valuemin':"0", 'aria-valuemax':"100" }, '0%')
])
]),
delYn ? '' :
m('ul', {class: 'position-relative list-inline mb-0 text-400 me-2 chat-gallery-option ml-10'}, [
m('li', {class: 'list-inline-item'}, [
downloadFlag ?
m('a', {
class: 'chat-option',
href: `${global.apiUrl}/api/message/download?${new URLSearchParams(downloadParam).toString()}`,
'ata-bs-toggle': "tooltip",
'data-bs-placement': "top",
'aria-label': "Forward",
'data-bs-original-title': "Forward"
}, [
m('i', {class: 'bi bi-download text-black', style: 'font-size: 14px;'})
]) : ''
])
]),
]),
insDate
])
])
])
}
/*상대방에게 보이는 메시지 정의*/
const yourMessage = (msg, pervMsg, date, nextDate, force) => {
const avatar = msg.insName
let attaches = [];
let insAvatar;
let insDate;
let tailFlag = false;
/*첨부파일 리스트가 없을시 강제 리스트 주입*/
if(msg.talkAttachDtos === null || msg.talkAttachDtos === undefined) msg.talkAttachDtos = [];
if(msg.message.includes('[매뉴얼]')) {
const manualParam = JSON.parse(msg.message)
return [yourManualMessage(msg, pervMsg, manualParam, avatar, date, nextDate, force)]
} else if(msg.talkAttachDtos.length > 0) {
let isImage = true;
msg.talkAttachDtos.forEach((cca) => {
if(!(cca.type.includes('image'))) {
isImage = false;
}
})
if(isImage) {
attaches = yourImageMessage(msg, pervMsg, avatar, date, nextDate, force)
} else {
attaches = yourFileMessage(msg, pervMsg, avatar, date, nextDate, force);
}
return [
attaches
]
} else {
if(force) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
} else {
if(date !== nextDate) {
insDate = m('div', {class:'text-400 fs-11 chat-date ml-10'}, date);
}
}
try {
if(global.yourOldDate !== date || pervMsg.attrs.className.includes('mine')) {
insAvatar = m('div', {class:"rounded-circle chat-avatar"}, avatar)
tailFlag = true;
global.yourOldDate = date
}
} catch(e) {}
let message = msg.message
let linkYn = false;
const urlRegex = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
const matches = message.match(urlRegex)
if(matches !== null) linkYn = true;
if(linkYn) {
if(message.includes('[ITSM]') || message.includes('[SCM]')) {
message = m.trust(message.replace(matches[0], `<div class="detail-wrapper"><div class="detail-btn btn-sm btn-info btn-color" data-href="${matches[0]}">자세히보기</div></div>`));
} else {
message = m.trust(message.replace(matches[0], `<a title="${matches[0]}" class="text-ellipsis" target="_blank" href="${matches[0]}">${matches[0]}</a>`));
}
}
return [
m('div', {class:'d-flex p-1 chat-text-wrapper your cus-show'}, [
m('div', {class: 'avatar avatar-l me-2'}, [
insAvatar
]),
m('div', {class:'flex-1'}, [
m('div', {class:'w-100'}, [
m('div', {class:'hover-actions-trigger d-flex align-items-center'}, [
m('div', {"data-line": `${msg.line}`, 'search-yn': `${msg.searchYn}`, class:`${tailFlag ? 'tail' : ''} chat-content-custom-font-size chat-message bg-200 p-2 rounded-3 ml-10 your`}, message)
]),
insDate
])
])
])
]
}
return [
attaches,
m('div', {class:'d-flex p-1 chat-text-wrapper your'}, [
m('div', {class: 'avatar avatar-l me-2'}, [
insAvatar
]),
m('div', {class:'flex-1'}, [
m('div', {class:'w-100'}, [
m('div', {class:'hover-actions-trigger d-flex align-items-center'}, [
m('div', {"data-line": `${msg.line}`, 'search-yn': `${msg.searchYn}`, class:`${tailFlag ? 'tail' : ''} chat-content-custom-font-size chat-message bg-200 p-2 rounded-3 ml-10 your`}, msg.message)
]),
insDate
])
])
])
]
}
const findParentElement = function(node, parentClass) {
let pa = node.parentElement;
if(pa.classList.contains(parentClass)) {
return pa;
} else {
return findParentElement(pa, parentClass)
}
}
export {infoMessage, systemMessage, dateMessage, talkMapping, messageMapping}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,492 @@
// Generated by CoffeeScript 1.7.1
/*
Stomp Over WebSocket http://www.jmesnil.net/stomp-websocket/doc/ | Apache License V2.0
Copyright (C) 2010-2013 [Jeff Mesnil](http://jmesnil.net/)
Copyright (C) 2012 [FuseSource, Inc.](http://fusesource.com)
*/
(function () {
var Byte, Client, Frame, Stomp,
__hasProp = {}.hasOwnProperty,
__slice = [].slice;
Byte = {
LF: '\x0A',
NULL: '\x00'
};
Frame = (function () {
var unmarshallSingle;
function Frame(command, headers, body) {
this.command = command;
this.headers = headers != null ? headers : {};
this.body = body != null ? body : '';
}
Frame.prototype.toString = function () {
var lines, name, skipContentLength, value, _ref;
lines = [this.command];
skipContentLength = this.headers['content-length'] === false ? true : false;
if (skipContentLength) {
delete this.headers['content-length'];
}
_ref = this.headers;
for (name in _ref) {
if (!__hasProp.call(_ref, name)) continue;
value = _ref[name];
lines.push("" + name + ":" + value);
}
if (this.body && !skipContentLength) {
lines.push("content-length:" + (Frame.sizeOfUTF8(this.body)));
}
lines.push(Byte.LF + this.body);
return lines.join(Byte.LF);
};
Frame.sizeOfUTF8 = function (s) {
if (s) {
return encodeURI(s).match(/%..|./g).length;
} else {
return 0;
}
};
unmarshallSingle = function (data) {
var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _len, _ref,
_ref1;
divider = data.search(RegExp("" + Byte.LF + Byte.LF));
headerLines = data.substring(0, divider).split(Byte.LF);
command = headerLines.shift();
headers = {};
trim = function (str) {
return str.replace(/^\s+|\s+$/g, '');
};
_ref = headerLines.reverse();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
idx = line.indexOf(':');
headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1));
}
body = '';
start = divider + 2;
if (headers['content-length']) {
len = parseInt(headers['content-length']);
body = ('' + data).substring(start, start + len);
} else {
chr = null;
for (i = _j = start, _ref1 = data.length; start <= _ref1 ? _j < _ref1 : _j > _ref1; i = start <= _ref1 ? ++_j : --_j) {
chr = data.charAt(i);
if (chr === Byte.NULL) {
break;
}
body += chr;
}
}
return new Frame(command, headers, body);
};
Frame.unmarshall = function (datas) {
var data;
return (function () {
var _i, _len, _ref, _results;
_ref = datas.split(RegExp("" + Byte.NULL + Byte.LF + "*"));
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
data = _ref[_i];
if ((data != null ? data.length : void 0) > 0) {
_results.push(unmarshallSingle(data));
}
}
return _results;
})();
};
Frame.marshall = function (command, headers, body) {
var frame;
frame = new Frame(command, headers, body);
return frame.toString() + Byte.NULL;
};
return Frame;
})();
Client = (function () {
var now;
function Client(ws) {
this.ws = ws;
this.ws.binaryType = "arraybuffer";
this.counter = 0;
this.connected = false;
this.heartbeat = {
outgoing: 10000,
incoming: 10000
};
this.maxWebSocketFrameSize = 16 * 1024;
this.subscriptions = {};
}
Client.prototype.debug = function (message) {
var _ref;
return typeof window !== "undefined" && window !== null ? (_ref = window.console) != null ? _ref.log(message) : void 0 : void 0;
};
now = function () {
if (Date.now) {
return Date.now();
} else {
return new Date().valueOf;
}
};
Client.prototype._transmit = function (command, headers, body) {
var out;
out = Frame.marshall(command, headers, body);
if (typeof this.debug === "function") {
this.debug(">>> " + out);
}
while (true) {
if (out.length > this.maxWebSocketFrameSize) {
this.ws.send(out.substring(0, this.maxWebSocketFrameSize));
out = out.substring(this.maxWebSocketFrameSize);
if (typeof this.debug === "function") {
this.debug("remaining = " + out.length);
}
} else {
return this.ws.send(out);
}
}
};
Client.prototype._setupHeartbeat = function (headers) {
var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1;
if ((_ref = headers.version) !== Stomp.VERSIONS.V1_1 && _ref !== Stomp.VERSIONS.V1_2) {
return;
}
_ref1 = (function () {
var _i, _len, _ref1, _results;
_ref1 = headers['heart-beat'].split(",");
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
_results.push(parseInt(v));
}
return _results;
})(), serverOutgoing = _ref1[0], serverIncoming = _ref1[1];
if (!(this.heartbeat.outgoing === 0 || serverIncoming === 0)) {
ttl = Math.max(this.heartbeat.outgoing, serverIncoming);
if (typeof this.debug === "function") {
this.debug("send PING every " + ttl + "ms");
}
this.pinger = Stomp.setInterval(ttl, (function (_this) {
return function () {
_this.ws.send(Byte.LF);
return typeof _this.debug === "function" ? _this.debug(">>> PING") : void 0;
};
})(this));
}
if (!(this.heartbeat.incoming === 0 || serverOutgoing === 0)) {
ttl = Math.max(this.heartbeat.incoming, serverOutgoing);
if (typeof this.debug === "function") {
this.debug("check PONG every " + ttl + "ms");
}
return this.ponger = Stomp.setInterval(ttl, (function (_this) {
return function () {
var delta;
delta = now() - _this.serverActivity;
if (delta > ttl * 2) {
if (typeof _this.debug === "function") {
_this.debug("did not receive server activity for the last " + delta + "ms");
}
return _this.ws.close();
}
};
})(this));
}
};
Client.prototype._parseConnect = function () {
var args, connectCallback, errorCallback, headers;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
headers = {};
switch (args.length) {
case 2:
headers = args[0], connectCallback = args[1];
break;
case 3:
if (args[1] instanceof Function) {
headers = args[0], connectCallback = args[1], errorCallback = args[2];
} else {
headers.login = args[0], headers.passcode = args[1], connectCallback = args[2];
}
break;
case 4:
headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3];
break;
default:
headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3], headers.host = args[4];
}
return [headers, connectCallback, errorCallback];
};
Client.prototype.connect = function () {
var args, errorCallback, headers, out;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
out = this._parseConnect.apply(this, args);
headers = out[0], this.connectCallback = out[1], errorCallback = out[2];
if (typeof this.debug === "function") {
this.debug("Opening Web Socket...");
}
this.ws.onmessage = (function (_this) {
return function (evt) {
var arr, c, client, data, frame, messageID, onreceive, subscription, _i, _len, _ref, _results;
data = typeof ArrayBuffer !== 'undefined' && evt.data instanceof ArrayBuffer ? (arr = new Uint8Array(evt.data), typeof _this.debug === "function" ? _this.debug("--- got data length: " + arr.length) : void 0, ((function () {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = arr.length; _i < _len; _i++) {
c = arr[_i];
_results.push(String.fromCharCode(c));
}
return _results;
})()).join('')) : evt.data;
_this.serverActivity = now();
if (data === Byte.LF) {
if (typeof _this.debug === "function") {
_this.debug("<<< PONG");
}
return;
}
if (typeof _this.debug === "function") {
_this.debug("<<< " + data);
}
_ref = Frame.unmarshall(data);
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
frame = _ref[_i];
switch (frame.command) {
case "CONNECTED":
if (typeof _this.debug === "function") {
_this.debug("connected to server " + frame.headers.server);
}
_this.connected = true;
_this._setupHeartbeat(frame.headers);
_results.push(typeof _this.connectCallback === "function" ? _this.connectCallback(frame) : void 0);
break;
case "MESSAGE":
subscription = frame.headers.subscription;
onreceive = _this.subscriptions[subscription] || _this.onreceive;
if (onreceive) {
client = _this;
messageID = frame.headers["message-id"];
frame.ack = function (headers) {
if (headers == null) {
headers = {};
}
return client.ack(messageID, subscription, headers);
};
frame.nack = function (headers) {
if (headers == null) {
headers = {};
}
return client.nack(messageID, subscription, headers);
};
_results.push(onreceive(frame));
} else {
_results.push(typeof _this.debug === "function" ? _this.debug("Unhandled received MESSAGE: " + frame) : void 0);
}
break;
case "RECEIPT":
_results.push(typeof _this.onreceipt === "function" ? _this.onreceipt(frame) : void 0);
break;
case "ERROR":
_results.push(typeof errorCallback === "function" ? errorCallback(frame) : void 0);
break;
default:
_results.push(typeof _this.debug === "function" ? _this.debug("Unhandled frame: " + frame) : void 0);
}
}
return _results;
};
})(this);
this.ws.onclose = (function (_this) {
return function () {
var msg;
msg = "Whoops! Lost connection to " + _this.ws.url;
if (typeof _this.debug === "function") {
_this.debug(msg);
}
_this._cleanUp();
return typeof errorCallback === "function" ? errorCallback(msg) : void 0;
};
})(this);
return this.ws.onopen = (function (_this) {
return function () {
if (typeof _this.debug === "function") {
_this.debug('Web Socket Opened...');
}
headers["accept-version"] = Stomp.VERSIONS.supportedVersions();
headers["heart-beat"] = [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(',');
return _this._transmit("CONNECT", headers);
};
})(this);
};
Client.prototype.disconnect = function (disconnectCallback, headers) {
if (headers == null) {
headers = {};
}
this._transmit("DISCONNECT", headers);
this.ws.onclose = null;
this.ws.close();
this._cleanUp();
return typeof disconnectCallback === "function" ? disconnectCallback() : void 0;
};
Client.prototype._cleanUp = function () {
this.connected = false;
if (this.pinger) {
Stomp.clearInterval(this.pinger);
}
if (this.ponger) {
return Stomp.clearInterval(this.ponger);
}
};
Client.prototype.send = function (destination, headers, body) {
if (headers == null) {
headers = {};
}
if (body == null) {
body = '';
}
headers.destination = destination;
return this._transmit("SEND", headers, body);
};
Client.prototype.subscribe = function (destination, callback, headers) {
var client;
if (headers == null) {
headers = {};
}
if (!headers.id) {
headers.id = "sub-" + this.counter++;
}
headers.destination = destination;
this.subscriptions[headers.id] = callback;
this._transmit("SUBSCRIBE", headers);
client = this;
return {
id: headers.id,
unsubscribe: function () {
return client.unsubscribe(headers.id);
}
};
};
Client.prototype.unsubscribe = function (id) {
delete this.subscriptions[id];
return this._transmit("UNSUBSCRIBE", {
id: id
});
};
Client.prototype.begin = function (transaction) {
var client, txid;
txid = transaction || "tx-" + this.counter++;
this._transmit("BEGIN", {
transaction: txid
});
client = this;
return {
id: txid,
commit: function () {
return client.commit(txid);
},
abort: function () {
return client.abort(txid);
}
};
};
Client.prototype.commit = function (transaction) {
return this._transmit("COMMIT", {
transaction: transaction
});
};
Client.prototype.abort = function (transaction) {
return this._transmit("ABORT", {
transaction: transaction
});
};
Client.prototype.ack = function (messageID, subscription, headers) {
if (headers == null) {
headers = {};
}
headers["message-id"] = messageID;
headers.subscription = subscription;
return this._transmit("ACK", headers);
};
Client.prototype.nack = function (messageID, subscription, headers) {
if (headers == null) {
headers = {};
}
headers["message-id"] = messageID;
headers.subscription = subscription;
return this._transmit("NACK", headers);
};
return Client;
})();
Stomp = {
VERSIONS: {
V1_0: '1.0',
V1_1: '1.1',
V1_2: '1.2',
supportedVersions: function () {
return '1.1,1.0';
}
},
client: function (url, protocols) {
var klass, ws;
if (protocols == null) {
protocols = ['v10.stomp', 'v11.stomp'];
}
klass = Stomp.WebSocketClass || WebSocket;
ws = new klass(url, protocols);
return new Client(ws);
},
over: function (ws) {
return new Client(ws);
},
Frame: Frame
};
if (typeof window !== "undefined" && window !== null) {
Stomp.setInterval = function (interval, f) {
return window.setInterval(f, interval);
};
Stomp.clearInterval = function (id) {
return window.clearInterval(id);
};
window.Stomp = Stomp;
} else {
Stomp.setInterval = function (interval, f) {
return setInterval(f, interval);
}
Stomp.clearInterval = function (id) {
return clearInterval(id);
};
self.Stomp = Stomp;
}
}).call(this);

View File

@@ -0,0 +1,572 @@
import m from 'http://talk.kospo.co.kr:3000/static/bundle/mithril-2.2.2/mithril.js'
import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js";
import {talkMapping} from "http://talk.kospo.co.kr:3000/static/js/module/render.js";
import SockJS from "http://talk.kospo.co.kr:3000/static/bundle/sockjs-client-1.6.1/sockjs.js";
import {getTalkList, getMessageAll, getMoreMessageAll} from "http://talk.kospo.co.kr:3000/static/js/module/apis.js";
import {HubEvent} from "http://talk.kospo.co.kr:3000/static/js/module/hubEvent.js";
import {getApInfo} from "http://talk.kospo.co.kr:3000/static/js/module/apis.js";
import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js";
import Hub from "http://talk.kospo.co.kr:3000/static/js/module/hub.js";
// 톡방 기능
let reConnectAttempts = 0;
let reConnectCnt = 0;
let errCnt = 0;
const talkEvent = {
// 소켓 연결
connect() {
const _this_ = this;
/*현재 서버 정보 호출*/
getApInfo().then((data) => {
global.currentServer = data.server
})
return new Promise((resolve, reject) => {
/*소켓연결*/
global.sockJS = new SockJS(
`${global.apiUrl}/stomp/talk`, {
Authentication: global.option.encSabun
}, {
transports: ['websocket'],
reconnectInterval: 500,
reconnectDelay: 500,
}
);
global.stomp = window.Stomp.over(global.sockJS);
global.stomp.heartbeat.outgoing = 20000;
global.stomp.heartbeat.incoming = 20000;
global.stomp.debug = (e) => {
if (e.includes('ERROR') || e.includes('Exception') || e.includes('failed')) {
// console.log(new Date().toString())
// console.error('STOMP error:', e);
}
};
/*stomp 연결*/
global.stomp.connect({Authentication: global.option.encSabun, location: 'TALK'}, function (frame) {
resolve();
})
global.stomp.onerror = (e) => {
console.log('err', e)
}
global.stomp.onclose = (e) => {
console.log('close', e)
}
const maxReconnectAttempts = 3;
const baseDelay = 10;
global.sockJS.onclose = (e) => {
if (e.wasClean) {
console.log('[Chat] WS Closed', new Date())
} else {
console.log('[Chat] WS Connecting...', new Date())
}
console.log(e)
/* 구독 해제 (남아 있는데이터 삭제) */
talkEvent.allUnsubscribe()
const delay = Math.min(baseDelay * Math.pow(100, reConnectAttempts), 2000)
const reConnectTimeout = setTimeout(() => {
if (reConnectAttempts < maxReconnectAttempts) {
reConnectAttempts++;
this.reConnect();
} else {
console.log('[Chat] Max Reconnect attempts reached.')
clearTimeout(reConnectTimeout)
/*서비스워커 종료*/
HubEvent.kill(global.talkParams({
type: 'KILL',
channelSabun: global.user.sabun
}))
global.forceKill = true;
global.shadowRoot.querySelector('.server-error').classList.remove('cus-hide')
}
}, delay)
}
})
},
reConnect: async () => {
console.log('reconnect')
// 소켓 설정 초기화
global.subscribeList = [];
/*현재 서버 정보 호출*/
let data = {};
try {
data = await getApInfo();
} catch (e) {
data['server'] = '';
}
/*ap 다른곳으로 이동시 서비스워커 재설치*/
if (global.currentServer !== data.server) {
HubEvent.close({
type: 'TAB_CLOSE',
tabId: global.tabId,
url: global.apiUrl,
sabun: global.user.sabun,
channelSabun: global.user.sabun,
site: global.currentUrl
})
global.hub.install().then(() => {
// 허브설정
HubEvent.start(global.talkParams({
type: 'START',
tabId: global.tabId
}))
});
}
talkEvent.connect().then(async () => {
global.hub.start();
// 톡방 재갱신
getTalkList(false).then(async () => {
// 톡방 메시지 재갱신
// getMessageAll(false)
getMoreMessageAll()
reConnectAttempts = 0;
console.log('global.init = true')
});
// 현재 탭 외 모든 탭 구독 해지
HubEvent.send(global.talkParams({
type: 'UNSUBSCRIBE',
tabId: global.tabId
}))
// 개인 사번 소켓 연결
try{global.subscribeList[global.user.sabun] = talkEvent.userSubscribe();}catch(e){}
// 업무별 소켓 연결
try{global.subscribeList[global.work.workId] = talkEvent.workSubscribe();}catch(e){}
global.init = true;
});
global.currentServer = data.server;
console.log('reConnectAttempts', reConnectAttempts)
},
// 오류 보수
// (추후 사용자 장애시 해당 기능 추가)
// 서비스워커 제거, 소켓 제거 후 재시작
repair: () => {
talkEvent.allUnsubscribe();
window.location.href = window.location.href;
},
// 개인 사번 구독
userSubscribe: () => {
return global.stomp.subscribe(`/exchange/user.exchange/user.${global.user.sabun}`, async function (content) {
const payload = JSON.parse(content.body);
if(payload.type === 'DEAD_MESSAGE') {
console.log('asdfasdfasdfasdfasdf');
global.shadowRoot.querySelector('.socket-error').classList.remove('cus-hide')
} else {
console.log('userSubscribe', payload)
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.send(payload)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
}
});
},
// 업무 구독
workSubscribe: () => {
return global.stomp.subscribe(`/exchange/work.exchange/work.${global.work.workId}`, async function (content) {
const payload = JSON.parse(content.body);
console.log('workSubscribe', payload)
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.work(payload)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
});
},
// 파일 구독
fileSubscribe: (payload) => {
global.fileSubscribeList[payload.talkId] = global.stomp.subscribe(`/exchange/file.exchange/file.${payload.talkId}`, async function (content) {
const payload = JSON.parse(content.body);
console.log('file subscribe', payload)
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.fileSend(payload)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
})
},
//톡방 구독
subscribe: (talkId) => {
return global.stomp.subscribe(`/exchange/talk.exchange/room.${talkId}`, async function (content) {
const payload = JSON.parse(content.body);
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.send(payload)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
});
},
// 구독 해지
unsubscribe: (talkId) => {
try {
global.subscribeList[talkId].unsubscribe()
} catch (e) {
}
delete global.subscribeList[talkId];
// global.subscribeList[talkId] = null;
},
// 전체 구독 해지 (구독과 관련된 모든 데이터 초기화)
allUnsubscribe: () => {
Object.keys(global.subscribeList).forEach((key) => {
try {
global.subscribeList[key].unsubscribe();
} catch (e) {
}
})
try {
global.subscribeList = [];
if(global.stomp && global.stomp.connected) {
global.stomp.disconnect(function() {
try {global.sockJS.close();} catch(e) {}
console.log('stomp 연결 해지 완료', global.stomp , global.sockJS)
global.stomp = null;
global.sockJS = null;
})
} else if(global.sockJS && global.sockJS.readyState === 1) {
try {global.sockJS.close();} catch(e) {}
console.log('sockjs 연결 해지 완료', global.stomp , global.sockJS)
global.sockJS = null;
}
} catch (e) {
console.log('allUnsubscribe error ', e)
}
},
// 톡 시작
start: (msgObj) => {
global.stomp.send(`/pub/talk.start.${msgObj.talkId}`, {}, JSON.stringify(msgObj))
},
// 톡 메시지 전송
send: async (msgObj) => {
if (Common.isMaster()) {
global.stomp.send(`/pub/talk.message.${msgObj.talkId}`, {}, JSON.stringify(msgObj))
} else {
msgObj.type = `SEND_${msgObj.type}`
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.send(msgObj)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
}
},
// 톡 종료
close: (msgObj) => {
global.stomp.send(`/pub/talk.close.${msgObj.talkId}`, {}, JSON.stringify(msgObj))
},
// 톡 첩부파일 전송
attach: async (msgObj) => {
if (Common.isMaster()) {
global.stomp.send(`/pub/talk.attach.${msgObj.talkId}`, {}, JSON.stringify(msgObj))
} else {
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.fileSend(msgObj)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
}
},
// 톡 생성
join: async (msgObj) => {
if (Common.isMaster()) {
global.stomp.send(`/pub/talk.enter.${msgObj.talkId}`, {}, JSON.stringify(msgObj))
} else {
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.send(msgObj)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
}
},
// 톡 떠나기
leave: async (msgObj) => {
if (Common.isMaster()) {
global.stomp.send(`/pub/talk.leave.${msgObj.talkId}`, {}, JSON.stringify(msgObj))
} else {
let sendFlag = false;
while (!sendFlag) {
if (global.serviceWorkerConnect) {
HubEvent.send(msgObj)
sendFlag = true;
} else {
global.registration.active.postMessage({"type": "WAKEUP"})
}
await Common.sleep(100)
}
global.serviceWorkerConnect = false;
}
},
// 시스템 변경
change: (msgObj) => {
/*유지보수 여러탭 구현 필요없음*/
global.stomp.send(`/pub/talk.change.${msgObj.talkId}`, {}, JSON.stringify(msgObj))
},
// 톡 아이디 생성
generateUUID: () => {
let d = new Date();
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
d + performance.now();
}
const uuid = 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxxxxxxyxxxxxxxxxy'.replace(/[xy]/g, function (c) {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
})
return uuid;
},
// 탭 아이디 생성
generateTabUUID: () => {
let d = new Date();
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
d + performance.now();
}
const uuid = 'xxxxxxxxxxxx4xxxyxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
})
return uuid;
},
/* 톡방 안에 담당자 및 업무명 변경*/
talkHeaderChange: (workNm, name) => {
const chatHeader = global.shadowRoot.querySelector('.chat-content-header');
if (workNm) {
chatHeader.querySelector('#work-nm').innerText = workNm
}
if (name) {
const names = name.split(',')
if (names.length === 1) {
chatHeader.querySelector('#work-sm-nm').classList.remove('cus-tooltip')
chatHeader.querySelector('#work-sm-nm').classList.remove('chat-inner-tooltip')
chatHeader.querySelector('#work-sm-nm').setAttribute("data-tooltip", '')
chatHeader.querySelector('#work-sm-nm').innerText = name;
} else {
chatHeader.querySelector('#work-sm-nm').classList.add('cus-tooltip')
chatHeader.querySelector('#work-sm-nm').classList.add('chat-inner-tooltip')
chatHeader.querySelector('#work-sm-nm').setAttribute("data-tooltip", name)
chatHeader.querySelector('#work-sm-nm').innerText = `${names[0]}${names.length - 1}`;
}
}
},
// 톡 내용 활성화
messageShow: () => {
talkEvent.messageClean();
global.shadowRoot.querySelector('#chat-tab').click()
global.shadowRoot.querySelector('#chat-0').classList.add('active')
global.element.chatSidebar.style.left = '-100%'
},
// 톡방 삭제
talkRemove: (talkId) => {
//톡방 삭제후 배지 카운트 재정의
global.talkData.forEach((talk, idx) => {
if (talk.talkId === talkId) {
console.log('talkRemove :', idx, talk)
// delete global.talkData[talk];
global.talkData.splice(idx, 1)
}
})
console.log(global.talkData)
talkMapping(global.talkData)
talkEvent.badgeChange()
},
// 톡방 보관
talkMark: (talkId) => {
let isMarkYn = false;
global.talkData.forEach((chat, idx) => {
if (chat.talkId === talkId) {
chat.markYn = !chat.markYn;
isMarkYn = chat.markYn;
if (chat.markYn) {
global.talkData.splice(idx, 1)
global.talkData = [chat, ...global.talkData]
}
}
})
if (!isMarkYn) {
global.talkData.sort((a, b) => {
if (!b.markYn) {
if (a.insDate > b.insDate) {
return -1
} else if (a.insDate < b.insDate) {
return 1
}
}
})
}
talkMapping(global.talkData)
},
// 톡방 정렬
talkSort: () => {
global.talkData.sort((a, b) => {
if (a.markYn) {
return -1;
} else {
if (a.lastMessageDate >= b.lastMessageDate) {
return -1;
} else if (a.lastMessageDate < b.lastMessageDate) {
return 1;
}
}
})
},
// 톡방 현재 스크롤 위치
messageScrollOriginalPositionMove: () => {
const contentBody = global.shadowRoot.querySelector('.chat-content-body');
const _contentScroll = contentBody.querySelector('.simplebar-content-wrapper')
_contentScroll.scrollTop = _contentScroll.scrollHeight - global.oldScrollPosition
},
// 스크롤 위치 가 변경 되었을시 메시지 미리보기
preMessageShow: (text) => {
const preMsg = global.shadowRoot.querySelector('.message-preview');
const msg = preMsg.querySelector('.msg');
msg.innerText = text;
preMsg.classList.remove('cus-hide');
},
// 메시지 삭제
messageClean: () => {
// 초기화 해야할 데이터
global.currDay = '0';
global.yourOldDate = '';
global.mineOldDate = '';
const chatContent = global.shadowRoot.querySelector('#chat-content');
const content = chatContent.querySelector('.simplebar-content');
m.render(content, []);
content.innerHTML = '';
global.element.chatEditor.innerHTML = '';
},
// 메인 뱃지 카운트 초기화
badgeChange: () => {
const badgeUnCount = global.talkData.reduce((a, b) => {
return Number(a) + Number(b.unReadCnt)
}, 0);
const chatBadge = global.shadowRoot.querySelector('.unread.badge');
if (badgeUnCount !== parseInt(0)) {
chatBadge.classList.remove('cus-hide');
} else {
chatBadge.classList.add('cus-hide');
}
chatBadge.innerText = badgeUnCount;
},
/*채팅룸 읾음 표시로 변경*/
readMessage: (talkId) => {
console.log('readmessage', talkId)
global.shadowRoot.querySelector(`div[data-talk-id="${talkId}"]`).classList.remove('unread-message')
const room = global.shadowRoot.querySelector(`div[data-talk-id="${talkId}"]`);
const badge = room.querySelector('.chat-list-badge')
const cacheTalk = global.talkData.filter((talk) => talk.talkId === talkId)[0];
try {
cacheTalk.unReadCnt = 0;
talkEvent.badgeChange();
badge.remove()
} catch (e) {/*badge 텍스트가 없을시 예외 처리*/
}
},
/*채팅방 타이핑에 따른 progress 호출*/
messageTyped: (msg) => {
let html = ''
html = `
<div class="d-flex p-1 your-dot-progress cus-show">
<div class="avatar avatar-l me-2">
<!--<img class="rounded-circle" src="../assets/img/team/5.jpg" alt="">-->
<div class="rounded-circle chat-avatar">
${msg.insName}
</div>
</div>
<div class="flex-1">
<div class="w-100">
<div class="stage your">
<div class="dot-typing"/>
</div>
</div>
</div>
</div>
`
const chatContent = global.shadowRoot.querySelector('#chat-content');
const content = chatContent.querySelector('.simplebar-content');
if(!content.querySelector('.your-dot-progress')) {
content.insertAdjacentHTML('beforeend', html)
}
},
/*채팅방 타이핑을 하지 않을시 progress 제거*/
messageUnTyped: (msg) => {
const chatContent = global.shadowRoot.querySelector('#chat-content');
const content = chatContent.querySelector('.simplebar-content');
const dotProgress = content.querySelector('.your-dot-progress')
if (dotProgress !== null) dotProgress.remove();
},
/*채팅리스트 메인 글 변경 */
talkTitleChange: (talkId, sabun) => {
const cacheTalk = global.talkData.filter((talk) => talk.talkId === talkId)[0];
cacheTalk.talkMembers = cacheTalk.talkMembers.filter((member) => (member.sabun === 'info' || member.sabun === global.user.sabun || member.sabun === sabun))
talkMapping(global.talkData)
}
}
export {talkEvent}

View File

@@ -0,0 +1,154 @@
// 전역 변수
import {talkEvent} from "./talkEvent.js";
const global = {
/*스톰프*/
stomp: null,
/*사용자 정보 */
user: null,
/*현페이지 업무정보*/
work: null,
/*api url정의*/
apiUrl: '',
/*헬프톡 생성 옵션*/
option: {},
/*헬프톡 content 루트 */
shadowRoot: null,
/*헬프톨 주요 엘리먼트 */
element: {},
/*채팅 날짜 정의*/
currDay: '',
/*채팅 상태글 이전 날짜*/
yourOldDate: '',
/*채팅 본인글 이전 날짜*/
mineOldDate: '',
/*톡방 메시지 스크롤 위치*/
oldScrollPosition: 0,
/*스크롤 top < 300 페이징 데이터 호출 여부*/
scrollMoreFlag: true,
/*채팅방 엘리먼트 변화 감지 하여 자동 스크롤 사용여부*/
scrollObserveFlag:true,
/* 불필요 변수 */
allVNode: [],
/* 채팅방 데이터 */
talkData: [],
/* 소켓 커넥션 및 브로드 캐스드 관리*/
channel: null,
/* 현재 접속 서버 */
currentServer: '',
/*시스템 강제 종료 여부*/
forceKill: false,
/* 채팅글 호출 파라미터 */
messageParams: {
'talkId': '',
'week': 1,
'row': 50,
'start': 0,
},
/* 현재 접속 url 파리미터 정보 */
requestParams: {},
/* 구독 목록 */
subscribeList : {},
// 파일 구독 목록
fileSubscribeList: {},
/* 현재 사이트 URL*/
currentUrl: '',
/* 에러 메시지 함수 */
notifier: null,
/* 브라우저 탭 아이디 */
tabId: '',
/* 방 생성자 */
chatCreator: null,
hub: null,
/*클립보드 정보*/
clipboardData: null,
clipboardObjectUrl: null,
// 서비스워커 연결 여부
serviceWorkerConnect: false,
// 소켓연결 제어
reConnect: false,
/* 로딩 여부 (새로고침시 reconnect 방지용)*/
init: false,
checker : {flag: false, inDate: ''},
talkParams : (obj) => {
return {
type: obj.type,
insSabun: global.user.sabun,
insName : global.user.name,
insDate : obj.insDate || '',
message: obj.message || '',
talkId: obj.talkId,
workId: obj.workId,
workNm: obj.workNm || '',
introOwner: obj.introOwner || '',
talkAttachDtos: obj.talkAttachDtos === undefined ? [] : obj.talkAttachDtos,
talkMessages: obj.talkMessages,
attach: obj.attach,
tabId: global.tabId
}
},
/*특정 파라미터 초기화(채팅방 나가기시)*/
reset: () => {
// 인포 메시지 삭제
const systemMessages = global.shadowRoot.querySelectorAll('.system-message');
Array.from(systemMessages).forEach((sm) => sm.remove());
// 사이드바 원위치
global.element.chatSidebar.style.left = 0;
// // 채팅 내용 호출 파라미터 초기화
global.currDay = ''
global.yourOldDate = '';
global.mineOldDate = '';
// global.messageParams.talkId = '';
// global.messageParams.week = 1;
global.scrollMoreFlag = true;
global.scrollObserveFlag = true;
// 검색 비활성화
global.searchClose();
/*작성된 메시지 제거*/
const msg = global.element.chatEditor.innerText.trim();
if(msg !== '') {
const talkId = localStorage.getItem(global.tabId)
const _this = global.shadowRoot.querySelector(`div[data-talk-id="${talkId}"]`)
const workId = _this.dataset.workId;
const workNm = _this.dataset.workNm;
talkEvent.send(global.talkParams({
type: "UNTYPED",
talkId: talkId,
workId: workId,
workNm: workNm
}))
global.element.chatEditor.innerHTML = '';
}
talkEvent.messageClean();
// localstorage 정보 제거
localStorage.removeItem(global.tabId)
localStorage.removeItem('workId')
localStorage.removeItem('workNm')
},
talkClean: () => {
//
console.log('clean')
global.currDay = ''
global.yourOldDate = '';
global.mineOldDate = '';
global.messageParams.talkId = '';
global.messageParams.week = 1;
global.scrollMoreFlag = true;
global.scrollObserveFlag = true;
},
searchClose: () => {
const searchCloseBtn = global.shadowRoot.querySelector('#chat-option.bi-x-lg');
if(searchCloseBtn) {
searchCloseBtn.click()
}
}
}
export {global}