mirror of
https://gitee.com/lijingbo-2021/open-anylink-web.git
synced 2025-12-30 02:52:26 +00:00
实现消息转发
This commit is contained in:
@@ -17,6 +17,8 @@ const avatarSize = computed(() => {
|
||||
return 50
|
||||
case 'small':
|
||||
return 30
|
||||
case 'tiny':
|
||||
return 24
|
||||
case 'default':
|
||||
default:
|
||||
return 40
|
||||
@@ -31,6 +33,8 @@ const svgSize = computed(() => {
|
||||
return 30
|
||||
case 'small':
|
||||
return 18
|
||||
case 'tiny':
|
||||
return 16
|
||||
case 'default':
|
||||
default:
|
||||
return 24
|
||||
|
||||
298
src/components/common/SelectSessionDialog.vue
Normal file
298
src/components/common/SelectSessionDialog.vue
Normal file
@@ -0,0 +1,298 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { Search, Close } from '@element-plus/icons-vue'
|
||||
import SessionTitleItem from '@/components/item/SessionTitleItem.vue'
|
||||
import HashNoData from '@/components/common/HasNoData.vue'
|
||||
import { userQueryService, userQueryByNickService } from '@/api/user'
|
||||
import { combineId, smartMatch } from '@/js/utils/common'
|
||||
import { useUserStore, useMessageStore } from '@/stores'
|
||||
import { MsgType } from '@/proto/msg'
|
||||
|
||||
const props = defineProps(['isShow', 'sessionListSortedKey'])
|
||||
const emit = defineEmits(['update:isShow', 'showUserCard', 'showGroupCard', 'confirm'])
|
||||
|
||||
const userData = useUserStore()
|
||||
const messageData = useMessageStore()
|
||||
|
||||
const selected = ref([])
|
||||
|
||||
const myAccount = computed(() => {
|
||||
return userData.user.account
|
||||
})
|
||||
|
||||
const searchKey = ref('')
|
||||
const optionsFromServer = ref({})
|
||||
|
||||
const optionsAll = computed(() => {
|
||||
return {
|
||||
...messageData.sessionList,
|
||||
...optionsFromServer.value
|
||||
}
|
||||
})
|
||||
|
||||
const optionKeys = computed(() => {
|
||||
const allKeys = [...props.sessionListSortedKey, ...Object.keys(optionsFromServer.value)]
|
||||
if (!searchKey.value) {
|
||||
return allKeys
|
||||
} else {
|
||||
const data = []
|
||||
allKeys.forEach((key) => {
|
||||
const item = optionsAll.value[key]
|
||||
if (
|
||||
item.sessionType === MsgType.CHAT &&
|
||||
(item.objectInfo.account === searchKey.value ||
|
||||
smartMatch(item.objectInfo.nickName, searchKey.value) ||
|
||||
smartMatch(item.mark, searchKey.value))
|
||||
) {
|
||||
data.push(key)
|
||||
} else if (
|
||||
item.sessionType === MsgType.GROUP_CHAT &&
|
||||
(item.objectInfo.groupId === searchKey.value ||
|
||||
smartMatch(item.objectInfo.groupName, searchKey.value) ||
|
||||
smartMatch(item.mark, searchKey.value))
|
||||
) {
|
||||
data.push(key)
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
})
|
||||
|
||||
let timer
|
||||
const onQuery = () => {
|
||||
if (!searchKey.value) return
|
||||
|
||||
clearTimeout(timer)
|
||||
const key = searchKey.value //在异步执行中,变量禁止使用响应式,因为在将来执行的时候响应式数据随时会发生改变
|
||||
timer = setTimeout(async () => {
|
||||
userQueryByNickService({ keyWords: key }).then((res) => {
|
||||
res.data.data?.forEach((item) => {
|
||||
const sessionId = combineId(myAccount.value, item.account)
|
||||
if (!messageData.sessionList[sessionId]) {
|
||||
// 这里先不create Session,点击确认转发才create Session
|
||||
optionsFromServer.value[sessionId] = {}
|
||||
optionsFromServer.value[sessionId].sessionId = sessionId
|
||||
optionsFromServer.value[sessionId].sessionType = MsgType.CHAT
|
||||
optionsFromServer.value[sessionId].mark = ''
|
||||
optionsFromServer.value[sessionId].objectInfo = item
|
||||
}
|
||||
})
|
||||
})
|
||||
const sessionId = combineId(myAccount.value, key)
|
||||
if (!messageData.sessionList[sessionId]) {
|
||||
userQueryService({ account: key }).then((res) => {
|
||||
if (res.data.data) {
|
||||
// 这里先不create Session,点击确认转发才create Session
|
||||
optionsFromServer.value[sessionId] = {}
|
||||
optionsFromServer.value[sessionId].sessionId = sessionId
|
||||
optionsFromServer.value[sessionId].sessionType = MsgType.CHAT
|
||||
optionsFromServer.value[sessionId].mark = ''
|
||||
optionsFromServer.value[sessionId].objectInfo = res.data.data
|
||||
}
|
||||
})
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const onShowUserCard = (account) => {
|
||||
emit('showUserCard', { account })
|
||||
}
|
||||
|
||||
const onShowGroupCard = (groupId) => {
|
||||
emit('showGroupCard', { groupId })
|
||||
}
|
||||
|
||||
const onConfirm = () => {
|
||||
const data = []
|
||||
selected.value.forEach((account) => {
|
||||
data.push(optionsAll.value[account])
|
||||
})
|
||||
emit('confirm', data)
|
||||
}
|
||||
|
||||
const onOpen = () => {
|
||||
searchKey.value = ''
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
emit('update:isShow', false)
|
||||
selected.value = []
|
||||
optionsFromServer.value = {}
|
||||
}
|
||||
|
||||
const onCancle = () => {
|
||||
emit('update:isShow', false)
|
||||
}
|
||||
|
||||
const onClearSelected = () => {
|
||||
selected.value = []
|
||||
}
|
||||
|
||||
const onRemoveSelectedItem = (index) => {
|
||||
selected.value.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog
|
||||
class="select-dialog"
|
||||
:model-value="props.isShow"
|
||||
:modal="false"
|
||||
:top="'30vh'"
|
||||
:width="'610px'"
|
||||
:z-index="1"
|
||||
style="border-radius: 10px"
|
||||
@open="onOpen"
|
||||
@close="onClose"
|
||||
>
|
||||
<template #header>
|
||||
<slot name="title"></slot>
|
||||
</template>
|
||||
<div class="main bdr-t bdr-b bdr-l bdr-r">
|
||||
<div class="left bdr-r">
|
||||
<el-input
|
||||
v-model.trim="searchKey"
|
||||
placeholder="搜索:昵称/账号/备注/群名称"
|
||||
:prefix-icon="Search"
|
||||
:clearable="true"
|
||||
@input="onQuery"
|
||||
/>
|
||||
<div v-if="optionKeys.length > 0" class="my-scrollbar" style="flex: 1; overflow-y: scroll">
|
||||
<el-checkbox-group v-model="selected">
|
||||
<el-checkbox v-for="item in optionKeys" :key="item" :value="item">
|
||||
<SessionTitleItem
|
||||
:session="optionsAll[item]"
|
||||
:keyWords="searchKey"
|
||||
@showUserCard="onShowUserCard"
|
||||
@showGroupCard="onShowGroupCard"
|
||||
></SessionTitleItem>
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<HashNoData v-else></HashNoData>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="head bdr-b">
|
||||
<div style="font-size: 13px; color: gray">
|
||||
{{ `已选择:${selected.length} 个会话` }}
|
||||
</div>
|
||||
<el-button type="info" size="small" @click="onClearSelected" plain>清空</el-button>
|
||||
</div>
|
||||
<div v-if="selected.length > 0" class="my-scrollbar" style="flex: 1; overflow-y: scroll">
|
||||
<div class="selected-item" v-for="(item, index) in selected" :key="index">
|
||||
<SessionTitleItem
|
||||
:session="optionsAll[item]"
|
||||
@showUserCard="onShowUserCard"
|
||||
@showGroupCard="onShowGroupCard"
|
||||
></SessionTitleItem>
|
||||
<el-button :icon="Close" size="small" circle @click="onRemoveSelectedItem(index)" />
|
||||
</div>
|
||||
</div>
|
||||
<HashNoData v-else></HashNoData>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="info" @click="onCancle" plain>取消</el-button>
|
||||
<el-button type="primary" @click="onConfirm" plain>确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
height: 360px;
|
||||
margin: 10px 0 10px 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.left {
|
||||
width: 49%;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.el-checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.el-checkbox {
|
||||
height: 45px;
|
||||
margin: 0 2px 2px 0;
|
||||
padding: 0 10px 0 10px;
|
||||
border-radius: 8px;
|
||||
color: black;
|
||||
|
||||
&:hover {
|
||||
background-color: #dedfe0;
|
||||
}
|
||||
}
|
||||
|
||||
.is-checked {
|
||||
background-color: #dedfe0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
padding: 10px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.head {
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.selected-item {
|
||||
height: 45px;
|
||||
margin: 0 0 2px 0;
|
||||
padding: 0 10px 0 10px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: black;
|
||||
--close-button-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: #dedfe0;
|
||||
--close-button-color: auto;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
border: none;
|
||||
color: var(--close-button-color);
|
||||
background-color: var(--close-button-background-color);
|
||||
|
||||
&:hover {
|
||||
--close-button-background-color: #f0f0f0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-input {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 25px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
141
src/components/item/SessionTitleItem.vue
Normal file
141
src/components/item/SessionTitleItem.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import UserAvatarIcon from '@/components/common/UserAvatarIcon.vue'
|
||||
import GroupAvatarIcon from '@/components/common/GroupAvatarIcon.vue'
|
||||
import { MsgType } from '@/proto/msg'
|
||||
import { useGroupStore } from '@/stores'
|
||||
import { highLightedText } from '@/js/utils/common'
|
||||
|
||||
/**
|
||||
* objectInfo:对象详情
|
||||
* keyWords:搜索关键字,用于高亮显示检索的关键字
|
||||
*/
|
||||
const props = defineProps(['session', 'keyWords'])
|
||||
const emit = defineEmits(['showUserCard', 'showGroupCard'])
|
||||
|
||||
const groupData = useGroupStore()
|
||||
|
||||
const showName = computed(() => {
|
||||
let name = ''
|
||||
if (props.session.sessionType === MsgType.CHAT) {
|
||||
name = props.session.objectInfo.nickName
|
||||
} else if (props.session.sessionType === MsgType.GROUP_CHAT) {
|
||||
name = props.session.objectInfo.groupName
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
|
||||
return props.session.mark ? `${props.session.mark}(${name})` : name
|
||||
})
|
||||
|
||||
const showId = computed(() => {
|
||||
if (props.session.sessionType === MsgType.CHAT) {
|
||||
return props.session.objectInfo.account
|
||||
} else if (props.session.sessionType === MsgType.GROUP_CHAT) {
|
||||
return props.session.objectInfo.groupId
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
const onShowUserCard = (e) => {
|
||||
e.preventDefault()
|
||||
emit('showUserCard', showId.value)
|
||||
}
|
||||
|
||||
const onShowGroupCard = (e) => {
|
||||
e.preventDefault()
|
||||
emit('showGroupCard', showId.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="session-wrapper">
|
||||
<div v-if="props.session.sessionType === MsgType.CHAT" class="user-session">
|
||||
<UserAvatarIcon
|
||||
class="user-session-avatar"
|
||||
:showName="showName"
|
||||
:showId="showId"
|
||||
:showAvatarThumb="props.session.objectInfo.avatarThumb"
|
||||
:size="'small'"
|
||||
@click="onShowUserCard"
|
||||
></UserAvatarIcon>
|
||||
<div class="user-session-info">
|
||||
<span
|
||||
class="name text-ellipsis"
|
||||
:title="showName"
|
||||
v-html="highLightedText(showName, props.keyWords, '#409eff')"
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
class="id"
|
||||
:title="showId"
|
||||
v-html="highLightedText(showId, props.keyWords, '#409eff', 'full')"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="props.session.sessionType === MsgType.GROUP_CHAT" class="group-session">
|
||||
<GroupAvatarIcon
|
||||
class="group-session-avatar"
|
||||
:avatarThumb="groupData.groupInfoList[props.session.objectInfo.groupId].avatarThumb"
|
||||
:size="'small'"
|
||||
@click="onShowGroupCard"
|
||||
></GroupAvatarIcon>
|
||||
<div class="group-session-info">
|
||||
<span
|
||||
class="name text-ellipsis"
|
||||
:title="showName"
|
||||
v-html="highLightedText(showName, props.keyWords, '#409eff')"
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
class="id"
|
||||
:title="showId"
|
||||
v-html="highLightedText(showId, props.keyWords, '#409eff', 'full')"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.session-wrapper {
|
||||
padding: 2px 0 2px 5px;
|
||||
|
||||
.user-session {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
|
||||
.user-session-info {
|
||||
max-width: 165px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
user-select: text;
|
||||
|
||||
.id {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.group-session {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
|
||||
.group-session-info {
|
||||
max-width: 165px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
user-select: text;
|
||||
|
||||
.id {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -19,6 +19,7 @@ import InputEditor from '@/views/message/components/InputEditor.vue'
|
||||
import MessageItem from '@/views/message/components/MessageItem.vue'
|
||||
import SessionTag from '@/views/message/components/SessionTag.vue'
|
||||
import SelectUserDialog from '@/components/common/SelectUserDialog.vue'
|
||||
import SelectSessionDialog from '@/components/common/SelectSessionDialog.vue'
|
||||
import {
|
||||
useUserStore,
|
||||
useSettingStore,
|
||||
@@ -522,7 +523,7 @@ const handleSelectedSession = async (sessionId) => {
|
||||
// 如果是群组,要加载成员列表(显示消息需要account,nickName,avatar信息)
|
||||
if (selectedSession.value.sessionType === MsgType.GROUP_CHAT) {
|
||||
// 没有members数据才需要加载成员列表,加载过了就不重复加载了
|
||||
if (!groupMembers.value) {
|
||||
if (!groupMembers.value && !isNotInGroup.value) {
|
||||
const res = await groupInfoService({ groupId: selectedSession.value.remoteId })
|
||||
groupData.setGroupInfo({
|
||||
groupId: selectedSession.value.remoteId,
|
||||
@@ -570,6 +571,92 @@ const sendRead = () => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理发送转发的消息
|
||||
*/
|
||||
const handleSendForwardMsg = async ({ session, content }) => {
|
||||
if (session.sessionType === MsgType.GROUP_CHAT && session.leave) {
|
||||
ElMessage.warning('您已离开该群或群已被解散')
|
||||
return
|
||||
}
|
||||
|
||||
if (session.sessionType === MsgType.GROUP_CHAT) {
|
||||
if (!groupData.groupMembersList[session.remoteId]) {
|
||||
const res = await groupInfoService({ groupId: session.remoteId })
|
||||
groupData.setGroupInfo({
|
||||
groupId: session.remoteId,
|
||||
groupInfo: res.data.data.groupInfo || {}
|
||||
})
|
||||
groupData.setGroupMembers({
|
||||
groupId: session.remoteId,
|
||||
members: res.data.data.members || {}
|
||||
})
|
||||
}
|
||||
|
||||
const meInGroup = groupData.groupMembersList[session.remoteId][myAccount.value]
|
||||
if (
|
||||
meInGroup.mutedMode === 1 ||
|
||||
(groupData.groupInfoList[session.remoteId].allMuted && meInGroup.mutedMode !== 2)
|
||||
) {
|
||||
ElMessage.warning('您已被禁言,请联系管理员')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const seq = uuidv4()
|
||||
const msg = {
|
||||
msgId: seq,
|
||||
seq: seq,
|
||||
sessionId: session.sessionId,
|
||||
fromId: myAccount.value,
|
||||
remoteId: session.remoteId,
|
||||
msgType: session.sessionType,
|
||||
content: content,
|
||||
status: msgSendStatus.PENDING,
|
||||
msgTime: new Date(),
|
||||
sendTime: new Date()
|
||||
}
|
||||
messageData.addMsgRecords(msg.sessionId, [msg])
|
||||
messageData.updateMsgKeySort(msg.sessionId)
|
||||
|
||||
if (selectedSessionId.value === msg.sessionId) {
|
||||
capacity.value++
|
||||
msgListReachBottom()
|
||||
}
|
||||
|
||||
const resendInterval = 2000 //2秒
|
||||
const before = (data) => {
|
||||
setTimeout(() => {
|
||||
if (msg.status === msgSendStatus.PENDING) {
|
||||
wsConnect.sendAgent(data)
|
||||
setTimeout(() => {
|
||||
if (msg.status === msgSendStatus.PENDING) {
|
||||
wsConnect.sendAgent(data)
|
||||
setTimeout(() => {
|
||||
if (msg.status === msgSendStatus.PENDING) {
|
||||
wsConnect.sendAgent(data)
|
||||
setTimeout(() => {
|
||||
if (msg.status === msgSendStatus.PENDING) {
|
||||
messageData.updateMsg(msg.sessionId, msg.msgId, {
|
||||
status: msgSendStatus.FAILED
|
||||
})
|
||||
ElMessage.error('消息发送失败')
|
||||
}
|
||||
}, resendInterval)
|
||||
}
|
||||
}, resendInterval)
|
||||
}
|
||||
}, resendInterval)
|
||||
}
|
||||
}, resendInterval)
|
||||
}
|
||||
|
||||
const after = (msgId) => {
|
||||
messageData.updateMsg(msg.sessionId, msg.msgId, { msgId, status: msgSendStatus.OK })
|
||||
}
|
||||
wsConnect.sendMsg(msg.sessionId, msg.remoteId, msg.msgType, msg.content, msg.seq, before, after)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送时先添加本地消息,可以立即渲染
|
||||
*/
|
||||
@@ -834,7 +921,7 @@ const onShowUserCard = ({ sessionId, account }) => {
|
||||
})
|
||||
}
|
||||
|
||||
if (messageData.sessionList[sessionId].sessionType === MsgType.GROUP_CHAT) {
|
||||
if (sessionId && messageData.sessionList[sessionId].sessionType === MsgType.GROUP_CHAT) {
|
||||
const groupId = selectedSession.value.remoteId
|
||||
groupData.setOneOfGroupMembers({
|
||||
groupId: groupId,
|
||||
@@ -1066,6 +1153,65 @@ const onSelectOprMenu = (label) => {
|
||||
}
|
||||
}
|
||||
|
||||
const isShowForwardMsgDialog = ref(false)
|
||||
let forwardMsg = {} // 待转发的消息
|
||||
const sessionListSortedKey = computed(() => {
|
||||
return sessionListSorted.value
|
||||
.filter((item) => {
|
||||
return !(item.sessionType === MsgType.GROUP_CHAT && item.leave)
|
||||
})
|
||||
.map((item) => item.sessionId)
|
||||
})
|
||||
|
||||
const showForwardMsgDialog = (msgId) => {
|
||||
forwardMsg = messageData.getMsg(selectedSessionId.value, msgId)
|
||||
isShowForwardMsgDialog.value = true
|
||||
}
|
||||
|
||||
const handleConfirmForwardMsg = async (sessions) => {
|
||||
const loadingInstance = ElLoading.service(el_loading_options)
|
||||
try {
|
||||
for (const item of sessions) {
|
||||
const sessionId = item.sessionId
|
||||
const remoteId = item.remoteId
|
||||
// 如果没有session,先创建session
|
||||
if (!messageData.sessionList[sessionId]) {
|
||||
const res = await msgChatCreateSessionService({
|
||||
sessionId: sessionId,
|
||||
remoteId: remoteId,
|
||||
sessionType: item.sessionType
|
||||
})
|
||||
messageData.addSession(res.data.data.session)
|
||||
}
|
||||
|
||||
await handleSendForwardMsg({
|
||||
session: item,
|
||||
content: forwardMsg.content
|
||||
.split(/(<.*?>)/)
|
||||
.map((item) => {
|
||||
const sliceStr = item.slice(1, -1)
|
||||
const index = sliceStr.indexOf('-')
|
||||
if (index !== -1) {
|
||||
const nickName = sliceStr.slice(index + 1)
|
||||
if (nickName) {
|
||||
return `@${nickName}`
|
||||
} else {
|
||||
return item
|
||||
}
|
||||
}
|
||||
return item
|
||||
})
|
||||
.join('')
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('forward msg error: ', error)
|
||||
} finally {
|
||||
loadingInstance.close()
|
||||
isShowForwardMsgDialog.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const showMenuAddOpr = (e) => {
|
||||
addOprMenuRef.value.handleShowMenu(e)
|
||||
}
|
||||
@@ -1307,6 +1453,7 @@ const onShowRecorder = () => {
|
||||
@resendMsg="handleResendMessage"
|
||||
@loadFinished="updateScroll"
|
||||
@showHighlight="handleShowHighlight"
|
||||
@forwardMsg="showForwardMsgDialog"
|
||||
></MessageItem>
|
||||
</MenuMsgMain>
|
||||
</div>
|
||||
@@ -1432,6 +1579,17 @@ const onShowRecorder = () => {
|
||||
<div style="font-size: 16px; font-weight: bold; white-space: nowrap">创建群组</div>
|
||||
</template>
|
||||
</SelectUserDialog>
|
||||
<SelectSessionDialog
|
||||
v-model:isShow="isShowForwardMsgDialog"
|
||||
:sessionListSortedKey="sessionListSortedKey"
|
||||
@showUserCard="onShowUserCard"
|
||||
@showGroupCard="onShowGroupCard"
|
||||
@confirm="handleConfirmForwardMsg"
|
||||
>
|
||||
<template #title>
|
||||
<div style="font-size: 16px; font-weight: bold; white-space: nowrap">转发消息</div>
|
||||
</template>
|
||||
</SelectSessionDialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -63,12 +63,6 @@ const menu = computed(() => {
|
||||
}
|
||||
|
||||
if (msgStatus.value === msgSendStatus.OK) {
|
||||
o.push({
|
||||
label: 'forward',
|
||||
desc: '转发',
|
||||
icon: markRaw(ForwardIcon),
|
||||
index: 1
|
||||
})
|
||||
o.push({
|
||||
label: 'multiSelect',
|
||||
desc: '多选',
|
||||
@@ -83,6 +77,15 @@ const menu = computed(() => {
|
||||
})
|
||||
}
|
||||
|
||||
if (msgStatus.value === msgSendStatus.OK && contentType.value !== msgContentType.RECORDING) {
|
||||
o.push({
|
||||
label: 'forward',
|
||||
desc: '转发',
|
||||
icon: markRaw(ForwardIcon),
|
||||
index: 1
|
||||
})
|
||||
}
|
||||
|
||||
if (
|
||||
myAccount.value === props.msg.fromId &&
|
||||
msgStatus.value === msgSendStatus.OK &&
|
||||
|
||||
@@ -44,7 +44,8 @@ const emit = defineEmits([
|
||||
'showGroupCard',
|
||||
'resendMsg',
|
||||
'loadFinished',
|
||||
'showHighlight'
|
||||
'showHighlight',
|
||||
'forwardMsg'
|
||||
])
|
||||
|
||||
const userData = useUserStore()
|
||||
@@ -224,7 +225,7 @@ const renderAt = (content) => {
|
||||
color: '#337ECC',
|
||||
fontWeight: account === myAccount.value || account === '0' ? 'bold' : 'normal'
|
||||
}
|
||||
return h('span', { style }, `@${nickName}`)
|
||||
return h('span', { style }, `@${nickName} `)
|
||||
} else {
|
||||
return h('span', `<${content}>`)
|
||||
}
|
||||
@@ -850,6 +851,9 @@ const onSelectMenuMsgItem = async (label) => {
|
||||
msgTime: msg.value.msgTime
|
||||
})
|
||||
break
|
||||
case 'forward':
|
||||
emit('forwardMsg', props.msgKey)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ const showDetailContent = computed(() => {
|
||||
}
|
||||
return item
|
||||
})
|
||||
.join(' ')
|
||||
.join('')
|
||||
}
|
||||
return formatDraft
|
||||
} else {
|
||||
@@ -324,7 +324,7 @@ const showDetailContent = computed(() => {
|
||||
}
|
||||
return item
|
||||
})
|
||||
.join(' ')
|
||||
.join('')
|
||||
return getGroupChatMsgTips(content)
|
||||
default:
|
||||
return ''
|
||||
|
||||
Reference in New Issue
Block a user