mirror of
https://github.com/kuaifan/dootask.git
synced 2026-01-15 03:08:11 +00:00
优化消息列表
This commit is contained in:
parent
d9cd7a93cc
commit
3f959918af
29
resources/assets/js/functions/utils.js
vendored
29
resources/assets/js/functions/utils.js
vendored
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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%;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user