优化消息列表

This commit is contained in:
kuaifan 2022-06-16 14:46:58 +08:00
parent d9cd7a93cc
commit 3f959918af
5 changed files with 251 additions and 214 deletions

View File

@ -45,5 +45,34 @@ module.exports = {
})
}
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;
}
}

View File

@ -4,21 +4,21 @@
<UserAvatar :userid="source.userid" :tooltipDisabled="source.userid == userId" :size="30"/>
</div>
<DialogView
ref="view"
:msg-data="source"
:dialog-type="dialogData.type"
:hide-percentage="isMyDialog"
:operate-visible="operateVisible"
:operate-action="operateVisible && source.id === operateItem.id"
@on-longpress="onLongpress"/>
@on-longpress="onLongpress"
@on-view-text="onViewText"
@on-view-file="onViewFile"
@on-emoji="onEmoji"/>
</div>
</template>
<script>
import {mapState} from "vuex";
import DialogView from "./DialogView";
import {Store} from "le5le-store";
export default {
name: "DialogItem",
@ -58,14 +58,6 @@ export default {
}
},
mounted() {
this.subscribe = Store.subscribe('dialogOperate', this.onOperate);
},
beforeDestroy() {
this.subscribe.unsubscribe();
},
computed: {
...mapState(['userId']),
@ -79,30 +71,36 @@ export default {
methods: {
onLongpress(e) {
Store.set('dialogLongpress', e);
this.dispatch("on-longpress", e)
},
onOperate({id, action, value}) {
if (id === this.source.id) {
switch (action) {
case "withdraw":
this.$refs.view.withdraw()
break;
onViewText(e) {
this.dispatch("on-view-text", e)
},
case "view":
this.$refs.view.viewFile()
break;
onViewFile(e) {
this.dispatch("on-view-file", e)
},
case "down":
this.$refs.view.downFile()
break;
onEmoji(e) {
this.dispatch("on-emoji", e)
},
case "emoji":
this.$refs.view.setEmoji(value)
break;
dispatch(event, arg) {
let parent = this.$parent
let name = parent.$options.name
while (parent && (!name || name !== 'virtual-list')) {
parent = parent.$parent
if (parent) {
name = parent.$options.name
}
}
},
if (parent) {
parent.$emit(event, arg)
}
}
}
}
</script>

View File

@ -72,7 +72,7 @@
v-for="(item, index) in msgData.emoji"
:key="index"
:class="{hasme: item.userids.includes(userId)}"
@click="setEmoji(item.symbol)">
@click="onEmoji(item.symbol)">
<div class="emoji-symbol no-dark-content">{{item.symbol}}</div>
<div class="emoji-num">{{item.userids.length}}</div>
</li>
@ -80,7 +80,7 @@
</div>
<!--等待/时间/阅读-->
<div v-if="emojiLoad > 0 || !msgData.created_at" class="dialog-foot"><Loading/></div>
<div v-if="!msgData.created_at" class="dialog-foot"><Loading/></div>
<div v-else class="dialog-foot">
<!--时间-->
<div v-if="timeShow" class="time" @click="timeShow=false">{{msgData.created_at}}</div>
@ -161,7 +161,6 @@ export default {
popperShow: false,
timeShow: false,
operateEnter: false,
emojiLoad: 0,
allList: [],
}
},
@ -360,184 +359,17 @@ export default {
});
},
withdraw() {
$A.modalConfirm({
content: `确定撤回此信息吗?`,
okText: '撤回',
loading: true,
onOk: () => {
this.$store.dispatch("call", {
url: 'dialog/msg/withdraw',
data: {
msg_id: this.msgData.id
},
}).then(() => {
$A.messageSuccess("消息已撤回");
this.$store.dispatch("forgetDialogMsg", this.msgData.id);
}).catch(({msg}) => {
$A.messageError(msg, 301);
}).finally(_ => {
this.$Modal.remove();
});
}
});
viewText(e) {
this.$emit("on-view-text", e)
},
viewText({target}) {
if (this.operateVisible) {
return
}
switch (target.nodeName) {
case "IMG":
if (target.classList.contains('browse')) {
this.viewPicture(target.currentSrc);
} else {
this.$store.state.previewImageIndex = 0;
this.$store.state.previewImageList = this.getTextImageInfos(target.outerHTML);
}
break;
case "SPAN":
if (target.classList.contains('mention') && target.classList.contains('task')) {
this.$store.dispatch("openTask", $A.runNum(target.getAttribute("data-id")));
}
break;
}
viewFile(e) {
this.$emit("on-view-file", e)
},
viewFile() {
if (this.operateVisible) {
return
}
const {msg} = this.msgData;
if (['jpg', 'jpeg', 'gif', 'png'].includes(msg.ext)) {
this.viewPicture(msg.path);
return
}
const path = `/single/file/msg/${this.msgData.id}`;
if (this.$Electron) {
this.$Electron.sendMessage('windowRouter', {
name: `file-msg-${this.msgData.id}`,
path: path,
userAgent: "/hideenOfficeTitle/",
force: false,
config: {
title: `${this.msgData.msg.name} (${$A.bytesToSize(this.msgData.msg.size)})`,
titleFixed: true,
parent: null,
width: Math.min(window.screen.availWidth, 1440),
height: Math.min(window.screen.availHeight, 900),
},
webPreferences: {
nodeIntegrationInSubFrames: msg.ext === 'drawio'
},
});
} else if (this.$isEEUiApp) {
$A.eeuiAppOpenPage({
pageType: 'app',
pageTitle: `${this.msgData.msg.name} (${$A.bytesToSize(this.msgData.msg.size)})`,
url: 'web.js',
params: {
titleFixed: true,
url: $A.rightDelete(window.location.href, window.location.hash) + `#${path}`
},
});
} else {
window.open($A.apiUrl(`..${path}`))
}
onEmoji(emoji) {
this.$emit("on-emoji", emoji)
},
viewPicture(currentUrl) {
const {dialog_id} = this.msgData;
const data = $A.cloneJSON(this.dialogMsgs.filter(item => {
if (item.dialog_id === dialog_id) {
if (item.type === 'file') {
return ['jpg', 'jpeg', 'gif', 'png'].includes(item.msg.ext);
} else if (item.type === 'text') {
return item.msg.text.match(/<img\s+class="browse"[^>]*?>/);
}
}
return false;
})).sort((a, b) => {
return a.id - b.id;
});
//
const list = [];
data.some(({type, msg}) => {
if (type === 'file') {
list.push({
src: msg.path,
width: msg.width,
height: msg.height,
})
} else if (type === 'text') {
list.push(...this.getTextImageInfos(msg.text))
}
})
//
const index = list.findIndex(({src}) => src === currentUrl);
if (index > -1) {
this.$store.state.previewImageIndex = index;
this.$store.state.previewImageList = list;
} else {
this.$store.state.previewImageIndex = 0;
this.$store.state.previewImageList = [currentUrl];
}
},
getTextImageInfos(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;
},
downFile() {
$A.modalConfirm({
title: '下载文件',
content: `${this.msgData.msg.name} (${$A.bytesToSize(this.msgData.msg.size)})`,
okText: '立即下载',
onOk: () => {
this.$store.dispatch('downUrl', $A.apiUrl(`dialog/msg/download?msg_id=${this.msgData.id}`))
}
});
},
setEmoji(emoji) {
setTimeout(_ => {
this.emojiLoad++;
}, 600);
this.$store.dispatch("call", {
url: 'dialog/msg/emoji',
data: {
msg_id: this.msgData.id,
emoji,
},
}).then(({data}) => {
this.$store.dispatch("saveDialogMsg", data);
}).catch(({msg}) => {
$A.messageError(msg);
}).finally(_ => {
this.emojiLoad--;
});
}
}
}
</script>

View File

@ -76,12 +76,22 @@
:data-key="'id'"
:data-sources="allMsgs"
:data-component="msgItem"
:extra-props="{dialogData, isMyDialog, operateVisible, operateItem}"
:estimate-size="78"
:keeps="80"
@scroll="onScroll"
@totop="loadNextPage">
<div slot="header" v-if="!dialogData.loading && allMsgs.length === 0" class="dialog-item nothing">{{$L('暂无消息')}}</div>
@totop="loadNextPage"
@on-longpress="onLongpress"
@on-view-text="onViewText"
@on-view-file="onViewFile"
@on-emoji="onEmoji">
<template slot="header">
<div v-if="(allMsgs.length === 0 && dialogData.loading > 0) || dialogData.hasMorePages" class="dialog-item loading"><Loading/></div>
<div v-else-if="allMsgs.length > 0" class="dialog-item loaded">{{$L('已加载全部消息')}}</div>
<div v-else class="dialog-item nothing">{{$L('暂无消息')}}</div>
</template>
</VirtualList>
<!--底部输入-->
@ -247,6 +257,7 @@ import ChatInput from "./ChatInput";
import VirtualList from 'vue-virtual-scroll-list'
import {Store} from "le5le-store";
import {textImagesInfo} from "../../../functions/utils";
export default {
name: "DialogWrapper",
@ -296,7 +307,6 @@ export default {
dialogDrag: false,
groupInfoShow: false,
dialogSubscribe: null,
navStyle: {},
@ -311,13 +321,8 @@ export default {
}
},
mounted () {
this.dialogSubscribe = Store.subscribe('dialogLongpress', this.onLongpress)
},
beforeDestroy() {
this.$store.dispatch('forgetInDialog', this._uid)
this.dialogSubscribe.unsubscribe();
},
computed: {
@ -937,14 +942,172 @@ export default {
break;
case "withdraw":
this.onWithdraw()
break;
case "view":
this.onViewFile()
break;
case "down":
this.onDownFile()
break;
case "emoji":
Store.set('dialogOperate', {id: this.operateItem.id, action, value});
this.onEmoji(value)
break;
}
})
},
onWithdraw() {
$A.modalConfirm({
content: `确定撤回此信息吗?`,
okText: '撤回',
loading: true,
onOk: () => {
this.$store.dispatch("call", {
url: 'dialog/msg/withdraw',
data: {
msg_id: this.operateItem.id
},
}).then(() => {
$A.messageSuccess("消息已撤回");
this.$store.dispatch("forgetDialogMsg", this.operateItem.id);
}).catch(({msg}) => {
$A.messageError(msg, 301);
}).finally(_ => {
this.$Modal.remove();
});
}
});
},
onViewText({target}) {
if (this.operateVisible) {
return
}
switch (target.nodeName) {
case "IMG":
if (target.classList.contains('browse')) {
this.onViewPicture(target.currentSrc);
} else {
this.$store.state.previewImageIndex = 0;
this.$store.state.previewImageList = textImagesInfo(target.outerHTML);
}
break;
case "SPAN":
if (target.classList.contains('mention') && target.classList.contains('task')) {
this.$store.dispatch("openTask", $A.runNum(target.getAttribute("data-id")));
}
break;
}
},
onViewFile() {
if (this.operateVisible) {
return
}
const {msg} = this.operateItem;
if (['jpg', 'jpeg', 'gif', 'png'].includes(msg.ext)) {
this.onViewPicture(msg.path);
return
}
const path = `/single/file/msg/${this.operateItem.id}`;
if (this.$Electron) {
this.$Electron.sendMessage('windowRouter', {
name: `file-msg-${this.operateItem.id}`,
path: path,
userAgent: "/hideenOfficeTitle/",
force: false,
config: {
title: `${msg.name} (${$A.bytesToSize(msg.size)})`,
titleFixed: true,
parent: null,
width: Math.min(window.screen.availWidth, 1440),
height: Math.min(window.screen.availHeight, 900),
},
webPreferences: {
nodeIntegrationInSubFrames: msg.ext === 'drawio'
},
});
} else if (this.$isEEUiApp) {
$A.eeuiAppOpenPage({
pageType: 'app',
pageTitle: `${msg.name} (${$A.bytesToSize(msg.size)})`,
url: 'web.js',
params: {
titleFixed: true,
url: $A.rightDelete(window.location.href, window.location.hash) + `#${path}`
},
});
} else {
window.open($A.apiUrl(`..${path}`))
}
},
onViewPicture(currentUrl) {
const data = $A.cloneJSON(this.dialogMsgs.filter(item => {
if (item.dialog_id === this.dialogId) {
if (item.type === 'file') {
return ['jpg', 'jpeg', 'gif', 'png'].includes(item.msg.ext);
} else if (item.type === 'text') {
return item.msg.text.match(/<img\s+class="browse"[^>]*?>/);
}
}
return false;
})).sort((a, b) => {
return a.id - b.id;
});
//
const list = [];
data.some(({type, msg}) => {
if (type === 'file') {
list.push({
src: msg.path,
width: msg.width,
height: msg.height,
})
} else if (type === 'text') {
list.push(...textImagesInfo(msg.text))
}
})
//
const index = list.findIndex(({src}) => src === currentUrl);
if (index > -1) {
this.$store.state.previewImageIndex = index;
this.$store.state.previewImageList = list;
} else {
this.$store.state.previewImageIndex = 0;
this.$store.state.previewImageList = [currentUrl];
}
},
onDownFile() {
$A.modalConfirm({
title: '下载文件',
content: `${this.operateItem.msg.name} (${$A.bytesToSize(this.operateItem.msg.size)})`,
okText: '立即下载',
onOk: () => {
this.$store.dispatch('downUrl', $A.apiUrl(`dialog/msg/download?msg_id=${this.operateItem.id}`))
}
});
},
onEmoji(emoji) {
this.$store.dispatch("call", {
url: 'dialog/msg/emoji',
data: {
msg_id: this.operateItem.id,
emoji,
},
}).then(({data}) => {
this.$store.dispatch("saveDialogMsg", data);
}).catch(({msg}) => {
$A.messageError(msg);
});
}
}
}
</script>

View File

@ -646,6 +646,21 @@
}
&.loading,
&.loaded {
color: rgba($primary-desc-color, 0.6);
font-size: 13px;
height: 20px;
box-sizing: content-box;
justify-content: center;
.common-loading {
margin: 0;
width: 18px;
height: 18px;
}
}
&.nothing {
position: absolute;
top: 50%;