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(`
`); 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], `