mirror of
https://github.com/kuaifan/dootask.git
synced 2026-02-27 20:30:32 +00:00
no message
This commit is contained in:
parent
500ed3a4d7
commit
a368e00b2f
33
resources/assets/js/functions/common.js
vendored
33
resources/assets/js/functions/common.js
vendored
@ -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
|
||||
|
||||
141
resources/assets/js/functions/utils.js
vendored
141
resources/assets/js/functions/utils.js
vendored
@ -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(/ /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
|
||||
105
resources/assets/js/functions/web.js
vendored
105
resources/assets/js/functions/web.js
vendored
@ -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(/ /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
|
||||
|
||||
@ -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"></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>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
}
|
||||
})
|
||||
//
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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}`,
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user