no message

This commit is contained in:
kuaifan 2022-06-30 16:07:50 +08:00
parent 500ed3a4d7
commit a368e00b2f
10 changed files with 166 additions and 181 deletions

View File

@ -1122,6 +1122,39 @@
return {width, height};
},
/**
* 阻止滑动穿透
* @param el
*/
scrollPreventThrough(el) {
if (!el) {
return;
}
if (el.getAttribute("data-prevent-through") === "yes") {
return;
}
el.setAttribute("data-prevent-through", "yes")
//
let targetY = null;
el.addEventListener('touchstart', function (e) {
targetY = Math.floor(e.targetTouches[0].clientY);
});
el.addEventListener('touchmove', function (e) {
// 检测可滚动区域的滚动事件,如果滑到了顶部或底部,阻止默认事件
let NewTargetY = Math.floor(e.targetTouches[0].clientY), //本次移动时鼠标的位置,用于计算
sTop = el.scrollTop, //当前滚动的距离
sH = el.scrollHeight, //可滚动区域的高度
lyBoxH = el.clientHeight; //可视区域的高度
if (sTop <= 0 && NewTargetY - targetY > 0) {
// 下拉页面到顶
e.preventDefault();
} else if (sTop >= sH - lyBoxH && NewTargetY - targetY < 0) {
// 上翻页面到底
e.preventDefault();
}
}, false);
},
/**
* 获取元素属性
* @param el

View File

@ -1,141 +0,0 @@
const assetsFunctionUtils = {
/**
* 消息格式化处理
* @param text
* @param userid
* @returns {string|*}
*/
textMsgFormat(text, userid) {
if (!text) {
return ""
}
const atReg = new RegExp(`<span class="mention user" data-id="${userid}">`, "g")
text = text.trim().replace(/(\n\x20*){3,}/g, "\n\n");
text = text.replace(/&nbsp;/g, ' ')
text = text.replace(/<p><\/p>/g, '<p><br/></p>')
text = text.replace(/\{\{RemoteURL\}\}/g, $A.apiUrl('../'))
text = text.replace(atReg, `<span class="mention me" data-id="${userid}">`)
// 处理内容连接
if (/https*:\/\//.test(text)) {
text = text.split(/(<[^>]*>)/g).map(string => {
if (string && !/<[^>]*>/.test(string)) {
string = string.replace(/(https*:\/\/)((\w|=|\?|\.|\/|&|-|:|\+|%|;|#)+)/g, "<a href=\"$1$2\" target=\"_blank\">$1$2</a>")
}
return string;
}).join("")
}
// 处理图片显示尺寸
const array = text.match(/<img\s+[^>]*?>/g);
if (array) {
const widthReg = new RegExp("width=\"(\\d+)\""),
heightReg = new RegExp("height=\"(\\d+)\"")
array.some(res => {
const widthMatch = res.match(widthReg),
heightMatch = res.match(heightReg);
if (widthMatch && heightMatch) {
const width = parseInt(widthMatch[1]),
height = parseInt(heightMatch[1]),
maxSize = res.indexOf("emoticon") > -1 ? 150 : 220;
const scale = $A.scaleToScale(width, height, maxSize, maxSize);
const value = res
.replace(widthReg, `original-width="${width}" width="${scale.width}"`)
.replace(heightReg, `original-height="${height}" height="${scale.height}"`)
text = text.replace(res, value)
}
})
}
return text;
},
/**
* 获取文本消息图片
* @param text
* @returns {*[]}
*/
textImagesInfo(text) {
const baseUrl = $A.apiUrl('../');
const array = text.match(new RegExp(`<img[^>]*?>`, "g"));
const list = [];
if (array) {
const srcReg = new RegExp("src=([\"'])([^'\"]*)\\1"),
widthReg = new RegExp("(original-)?width=\"(\\d+)\""),
heightReg = new RegExp("(original-)?height=\"(\\d+)\"")
array.some(res => {
const srcMatch = res.match(srcReg),
widthMatch = res.match(widthReg),
heightMatch = res.match(heightReg);
if (srcMatch) {
list.push({
src: srcMatch[2].replace(/\{\{RemoteURL\}\}/g, baseUrl),
width: widthMatch ? widthMatch[2] : -1,
height: heightMatch ? heightMatch[2] : -1,
})
}
})
}
return list;
},
/**
* 消息简单描述
* @param data
* @returns {string|*}
*/
msgSimpleDesc(data) {
if ($A.isJson(data)) {
switch (data.type) {
case 'text':
return $A.getMsgTextPreview(data.msg.text)
case 'record':
return `[${$A.L('语音')}]`
case 'meeting':
return `[${$A.L('会议')}] ${data.msg.name}`
case 'file':
if (data.msg.type == 'img') {
return `[${$A.L('图片')}]`
}
return `[${$A.L('文件')}] ${data.msg.name}`
case 'tag':
return `[${$A.L(data.msg.action === 'remove' ? '取消标注' : '标注')}] ${assetsFunctionUtils.msgSimpleDesc(data.msg.data)}`
default:
return `[${$A.L('未知的消息')}]`
}
}
return '';
},
/**
* 阻止滑动穿透
* @param el
*/
scrollPreventThrough(el) {
if (!el) {
return;
}
if (el.getAttribute("data-prevent-through") === "yes") {
return;
}
el.setAttribute("data-prevent-through", "yes")
//
let targetY = null;
el.addEventListener('touchstart', function (e) {
targetY = Math.floor(e.targetTouches[0].clientY);
});
el.addEventListener('touchmove', function (e) {
// 检测可滚动区域的滚动事件,如果滑到了顶部或底部,阻止默认事件
let NewTargetY = Math.floor(e.targetTouches[0].clientY), //本次移动时鼠标的位置,用于计算
sTop = el.scrollTop, //当前滚动的距离
sH = el.scrollHeight, //可滚动区域的高度
lyBoxH = el.clientHeight; //可视区域的高度
if (sTop <= 0 && NewTargetY - targetY > 0) {
// 下拉页面到顶
e.preventDefault();
} else if (sTop >= sH - lyBoxH && NewTargetY - targetY < 0) {
// 上翻页面到底
e.preventDefault();
}
}, false);
},
}
module.exports = assetsFunctionUtils

View File

@ -391,6 +391,111 @@
return text.replace(/<[^>]+>/g,"")
},
/**
* 消息格式化处理
* @param text
* @param userid
* @returns {string|*}
*/
formatTextMsg(text, userid) {
if (!text) {
return ""
}
const atReg = new RegExp(`<span class="mention user" data-id="${userid}">`, "g")
text = text.trim().replace(/(\n\x20*){3,}/g, "\n\n");
text = text.replace(/&nbsp;/g, ' ')
text = text.replace(/<p><\/p>/g, '<p><br/></p>')
text = text.replace(/\{\{RemoteURL\}\}/g, $A.apiUrl('../'))
text = text.replace(atReg, `<span class="mention me" data-id="${userid}">`)
// 处理内容连接
if (/https*:\/\//.test(text)) {
text = text.split(/(<[^>]*>)/g).map(string => {
if (string && !/<[^>]*>/.test(string)) {
string = string.replace(/(https*:\/\/)((\w|=|\?|\.|\/|&|-|:|\+|%|;|#)+)/g, "<a href=\"$1$2\" target=\"_blank\">$1$2</a>")
}
return string;
}).join("")
}
// 处理图片显示尺寸
const array = text.match(/<img\s+[^>]*?>/g);
if (array) {
const widthReg = new RegExp("width=\"(\\d+)\""),
heightReg = new RegExp("height=\"(\\d+)\"")
array.some(res => {
const widthMatch = res.match(widthReg),
heightMatch = res.match(heightReg);
if (widthMatch && heightMatch) {
const width = parseInt(widthMatch[1]),
height = parseInt(heightMatch[1]),
maxSize = res.indexOf("emoticon") > -1 ? 150 : 220;
const scale = $A.scaleToScale(width, height, maxSize, maxSize);
const value = res
.replace(widthReg, `original-width="${width}" width="${scale.width}"`)
.replace(heightReg, `original-height="${height}" height="${scale.height}"`)
text = text.replace(res, value)
}
})
}
return text;
},
/**
* 获取文本消息图片
* @param text
* @returns {*[]}
*/
getTextImagesInfo(text) {
const baseUrl = $A.apiUrl('../');
const array = text.match(new RegExp(`<img[^>]*?>`, "g"));
const list = [];
if (array) {
const srcReg = new RegExp("src=([\"'])([^'\"]*)\\1"),
widthReg = new RegExp("(original-)?width=\"(\\d+)\""),
heightReg = new RegExp("(original-)?height=\"(\\d+)\"")
array.some(res => {
const srcMatch = res.match(srcReg),
widthMatch = res.match(widthReg),
heightMatch = res.match(heightReg);
if (srcMatch) {
list.push({
src: srcMatch[2].replace(/\{\{RemoteURL\}\}/g, baseUrl),
width: widthMatch ? widthMatch[2] : -1,
height: heightMatch ? heightMatch[2] : -1,
})
}
})
}
return list;
},
/**
* 消息简单描述
* @param data
* @returns {string|*}
*/
getMsgSimpleDesc(data) {
if ($A.isJson(data)) {
switch (data.type) {
case 'text':
return $A.getMsgTextPreview(data.msg.text)
case 'record':
return `[${$A.L('语音')}]`
case 'meeting':
return `[${$A.L('会议')}] ${data.msg.name}`
case 'file':
if (data.msg.type == 'img') {
return `[${$A.L('图片')}]`
}
return `[${$A.L('文件')}] ${data.msg.name}`
case 'tag':
return `[${$A.L(data.msg.action === 'remove' ? '取消标注' : '标注')}] ${$A.getMsgSimpleDesc(data.msg.data)}`
default:
return `[${$A.L('未知的消息')}]`
}
}
return '';
},
/**
* 获取文件标题
* @param file

View File

@ -4,7 +4,7 @@
<!-- 回复 -->
<div v-if="replyData" class="chat-reply">
<UserAvatar :userid="replyData.userid" :show-icon="false" :show-name="true" :tooltip-disabled="true"/>
<div class="reply-desc">{{formatMsgDesc(replyData)}}</div>
<div class="reply-desc">{{$A.getMsgSimpleDesc(replyData)}}</div>
<i class="taskfont" @click.stop="onCancelReply">&#xe6e5;</i>
</div>
@ -132,7 +132,6 @@ import touchmouse from "../../../../directives/touchmouse";
import TransferDom from "../../../../directives/transfer-dom";
import clickoutside from "../../../../directives/clickoutside";
import {Store} from "le5le-store";
import {scrollPreventThrough, msgSimpleDesc} from "../../../../functions/utils";
export default {
name: 'ChatInput',
@ -526,7 +525,7 @@ export default {
containers[i].classList.remove("user-mention");
containers[i].classList.remove("task-mention");
containers[i].classList.add(mentionName);
scrollPreventThrough(containers[i]);
$A.scrollPreventThrough(containers[i]);
}
this.getMentionSource(mentionChar, searchTerm, array => {
const values = [];
@ -1146,10 +1145,6 @@ export default {
this.$emit('on-file', postFiles)
}
},
formatMsgDesc(data) {
return msgSimpleDesc(data);
},
}
}
</script>

View File

@ -3,7 +3,7 @@
<div v-if="source.type === 'tag'" class="dialog-tag" @click="onViewTag">
<div class="tag-user"><UserAvatar :userid="source.userid" :tooltipDisabled="source.userid == userId" :show-name="true" :show-icon="false"/></div>
{{$L(source.msg.action === 'remove' ? '取消标注' : '标注了')}}
"{{formatMsgDesc(source.msg.data)}}"
"{{$A.getMsgSimpleDesc(source.msg.data)}}"
</div>
<template v-else>
<div class="dialog-avatar">
@ -29,7 +29,6 @@
<script>
import {mapState} from "vuex";
import DialogView from "./DialogView";
import {msgSimpleDesc} from "../../../functions/utils";
export default {
name: "DialogItem",
@ -89,10 +88,6 @@ export default {
},
methods: {
formatMsgDesc(data) {
return msgSimpleDesc(data)
},
onViewTag() {
this.onViewReply({
msg_id: this.source.id,

View File

@ -12,13 +12,13 @@
<!--回复-->
<div v-if="!hideReply && msgData.reply_data" class="dialog-reply no-dark-content" @click="viewReply">
<UserAvatar :userid="msgData.reply_data.userid" :show-icon="false" :show-name="true" :tooltip-disabled="true"/>
<div class="reply-desc">{{formatMsgDesc(msgData.reply_data)}}</div>
<div class="reply-desc">{{$A.getMsgSimpleDesc(msgData.reply_data)}}</div>
</div>
<!--详情-->
<div class="dialog-content" :class="contentClass">
<!--文本-->
<div v-if="msgData.type === 'text'" class="content-text no-dark-content">
<pre @click="viewText" v-html="textMsg(msgData.msg.text)"></pre>
<pre @click="viewText" v-html="$A.formatTextMsg(msgData.msg.text, userId)"></pre>
</div>
<!--文件-->
<div v-else-if="msgData.type === 'file'" :class="`content-file ${msgData.msg.type}`">
@ -137,7 +137,6 @@ import WCircle from "../../../components/WCircle";
import {mapGetters, mapState} from "vuex";
import {Store} from "le5le-store";
import longpress from "../../../directives/longpress";
import {textMsgFormat, msgSimpleDesc} from "../../../functions/utils";
export default {
name: "DialogView",
@ -315,10 +314,6 @@ export default {
});
},
textMsg(text) {
return textMsgFormat(text, this.userId);
},
recordStyle(info) {
const {duration} = info;
const width = 50 + Math.min(180, Math.floor(duration / 150));
@ -360,10 +355,6 @@ export default {
return {};
},
formatMsgDesc(data) {
return msgSimpleDesc(data)
},
playRecord() {
if (this.operateVisible) {
return

View File

@ -295,7 +295,6 @@ import ChatInput from "./ChatInput";
import VirtualList from 'vue-virtual-scroll-list-hi'
import {Store} from "le5le-store";
import {textImagesInfo} from "../../../functions/utils";
export default {
name: "DialogWrapper",
@ -1267,7 +1266,7 @@ export default {
this.onViewPicture(target.currentSrc);
} else {
this.$store.state.previewImageIndex = 0;
this.$store.state.previewImageList = textImagesInfo(target.outerHTML);
this.$store.state.previewImageList = $A.getTextImagesInfo(target.outerHTML);
}
break;
@ -1347,7 +1346,7 @@ export default {
height: msg.height,
})
} else if (type === 'text') {
list.push(...textImagesInfo(msg.text))
list.push(...$A.getTextImagesInfo(msg.text))
}
})
//

View File

@ -75,7 +75,7 @@
</template>
<div class="last-text">
<em v-if="formatMsgEmojiDesc(dialog.last_msg)">{{formatMsgEmojiDesc(dialog.last_msg)}}</em>
<span>{{formatMsgDesc(dialog.last_msg)}}</span>
<span>{{$A.getMsgSimpleDesc(dialog.last_msg)}}</span>
</div>
</div>
</div>
@ -153,7 +153,6 @@ import {mapState} from "vuex";
import DialogWrapper from "./components/DialogWrapper";
import ScrollerY from "../../components/ScrollerY";
import longpress from "../../directives/longpress";
import {msgSimpleDesc} from "../../functions/utils";
export default {
components: {ScrollerY, DialogWrapper},
@ -604,10 +603,6 @@ export default {
return null;
},
formatMsgDesc(data) {
return msgSimpleDesc(data);
},
lastMsgReadDone(data) {
if ($A.isJson(data)) {
const {userid, percentage} = data;

View File

@ -148,7 +148,7 @@ export default {
break;
case 'privacy':
window.open($A.apiUrl('../privacy.html'))
this.openPrivacy();
break;
case 'index':
@ -161,6 +161,24 @@ export default {
}
},
openPrivacy() {
const url = $A.apiUrl('../privacy.html')
if (this.$isEEUiApp) {
$A.eeuiAppOpenPage({
pageType: 'app',
pageTitle: ' ',
url: 'web.js',
params: {
url,
browser: true,
showProgress: true,
},
});
} else {
window.open(url)
}
},
classNameRoute(path, divided) {
return {
"active": this.windowLarge && this.routeName === `manage-setting-${path}`,

View File

@ -8,7 +8,7 @@
<Drawio v-else-if="isType('drawio')" v-model="msgDetail.content" :title="msgDetail.msg.name" readOnly/>
<Minder v-else-if="isType('mind')" :value="msgDetail.content" readOnly/>
<template v-else-if="isType('code')">
<div v-if="isLongText(msgDetail.msg.name)" class="view-code" v-html="longTextFormat(msgDetail.content.content)"></div>
<div v-if="isLongText(msgDetail.msg.name)" class="view-code" v-html="$A.formatTextMsg(msgDetail.content.content, userId)"></div>
<AceEditor v-else v-model="msgDetail.content.content" :ext="msgDetail.msg.ext" class="view-editor" readOnly/>
</template>
<OnlyOffice v-else-if="isType('office')" v-model="officeContent" :code="officeCode" :documentKey="documentKey" readOnly/>
@ -64,7 +64,6 @@
<script>
import Vue from 'vue'
import Minder from '../../components/Minder'
import {textMsgFormat} from "../../functions/utils";
import {mapState} from "vuex";
import IFrame from "../manage/components/IFrame";
Vue.use(Minder)
@ -186,10 +185,6 @@ export default {
isLongText(name) {
return /^LongText-/.test(name)
},
longTextFormat(text) {
return textMsgFormat(text, this.userId)
},
}
}
</script>