✨ feat(im): 优化 message 的导入
parent
56b0630847
commit
122b1ba748
|
|
@ -51,7 +51,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, onUnmounted, watch } from 'vue'
|
import { computed, onMounted, onUnmounted, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessage } from 'element-plus'
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
|
||||||
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
||||||
import { getSimpleUser } from '@/api/system/user'
|
import { getSimpleUser } from '@/api/system/user'
|
||||||
|
|
@ -70,6 +70,7 @@ const conversationStore = useConversationStore()
|
||||||
const friendStore = useFriendStore()
|
const friendStore = useFriendStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
const card = computed(() => uiStore.userInfoCard)
|
const card = computed(() => uiStore.userInfoCard)
|
||||||
const user = computed(() => card.value.user)
|
const user = computed(() => card.value.user)
|
||||||
|
|
@ -161,14 +162,14 @@ async function handleAddFriend() {
|
||||||
nickname: user.value.nickname,
|
nickname: user.value.nickname,
|
||||||
avatar: user.value.avatar
|
avatar: user.value.avatar
|
||||||
})
|
})
|
||||||
ElMessage.success('已添加好友')
|
message.success('已添加好友')
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(
|
console.error(
|
||||||
'[IM] 添加好友失败',
|
'[IM] 添加好友失败',
|
||||||
{ userId: user.value?.id, nickname: user.value?.nickname },
|
{ userId: user.value?.id, nickname: user.value?.nickname },
|
||||||
e
|
e
|
||||||
)
|
)
|
||||||
ElMessage.error(e?.message || '添加好友失败')
|
message.error(e?.message || '添加好友失败')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,10 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
import Icon from '@/components/Icon/src/Icon.vue'
|
import Icon from '@/components/Icon/src/Icon.vue'
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
import { useConversationStore } from '../../../../store/conversationStore'
|
import { useConversationStore } from '../../../../store/conversationStore'
|
||||||
import { useFriendStore } from '../../../../store/friendStore'
|
import { useFriendStore } from '../../../../store/friendStore'
|
||||||
import { useGroupStore } from '../../../../store/groupStore'
|
import { useGroupStore } from '../../../../store/groupStore'
|
||||||
|
|
@ -96,6 +96,7 @@ const conversationStore = useConversationStore()
|
||||||
const friendStore = useFriendStore()
|
const friendStore = useFriendStore()
|
||||||
const groupStore = useGroupStore()
|
const groupStore = useGroupStore()
|
||||||
const uiStore = useImUiStore()
|
const uiStore = useImUiStore()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
const isActive = computed(
|
const isActive = computed(
|
||||||
() =>
|
() =>
|
||||||
|
|
@ -163,7 +164,7 @@ function handleMuted() {
|
||||||
: groupStore.setMuted(targetId, next)
|
: groupStore.setMuted(targetId, next)
|
||||||
sync.catch((e) => {
|
sync.catch((e) => {
|
||||||
console.error('[IM] 切换免打扰失败', e)
|
console.error('[IM] 切换免打扰失败', e)
|
||||||
ElMessage.error('切换免打扰失败')
|
message.error('切换免打扰失败')
|
||||||
conversationStore.setMuted(type, targetId, !next)
|
conversationStore.setMuted(type, targetId, !next)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -171,9 +172,7 @@ function handleMuted() {
|
||||||
/** 删除会话:二次确认后软删(用户取消走 catch 静默) */
|
/** 删除会话:二次确认后软删(用户取消走 catch 静默) */
|
||||||
async function handleDelete() {
|
async function handleDelete() {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(`确定删除与「${props.conversation.name}」的会话吗?`, '删除会话', {
|
await message.confirm(`确定删除与「${props.conversation.name}」的会话吗?`, '删除会话')
|
||||||
type: 'warning'
|
|
||||||
})
|
|
||||||
conversationStore.removeConversation(props.conversation.type, props.conversation.targetId)
|
conversationStore.removeConversation(props.conversation.type, props.conversation.targetId)
|
||||||
} catch {
|
} catch {
|
||||||
// 用户取消
|
// 用户取消
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
|
||||||
import Icon from '@/components/Icon/src/Icon.vue'
|
import Icon from '@/components/Icon/src/Icon.vue'
|
||||||
import { updateFile } from '@/api/infra/file'
|
import { updateFile } from '@/api/infra/file'
|
||||||
|
|
@ -142,6 +142,7 @@ defineOptions({ name: 'ImMessageInput' })
|
||||||
const conversationStore = useConversationStore()
|
const conversationStore = useConversationStore()
|
||||||
const groupStore = useGroupStore()
|
const groupStore = useGroupStore()
|
||||||
const { send, sendRaw } = useMessageSender()
|
const { send, sendRaw } = useMessageSender()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
const editorRef = useTemplateRef<HTMLDivElement>('editorRef')
|
const editorRef = useTemplateRef<HTMLDivElement>('editorRef')
|
||||||
const imageInputRef = useTemplateRef<HTMLInputElement>('imageInputRef')
|
const imageInputRef = useTemplateRef<HTMLInputElement>('imageInputRef')
|
||||||
|
|
@ -627,7 +628,7 @@ async function uploadAndSendImage(file: File) {
|
||||||
await sendRaw(ImMessageType.IMAGE, serializeMessage<ImageMessage>({ url }))
|
await sendRaw(ImMessageType.IMAGE, serializeMessage<ImageMessage>({ url }))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[IM] 图片上传失败:', err)
|
console.error('[IM] 图片上传失败:', err)
|
||||||
ElMessage.error('图片上传失败')
|
message.error('图片上传失败')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -646,7 +647,7 @@ async function uploadAndSendFile(file: File) {
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[IM] 文件上传失败:', err)
|
console.error('[IM] 文件上传失败:', err)
|
||||||
ElMessage.error('文件上传失败')
|
message.error('文件上传失败')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -689,7 +690,7 @@ async function onVoiceSend(payload: { blob: Blob; duration: number }) {
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[IM] 语音上传失败:', err)
|
console.error('[IM] 语音上传失败:', err)
|
||||||
ElMessage.error('语音上传失败')
|
message.error('语音上传失败')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
import { formatSeconds } from '@/utils/formatTime'
|
import { formatSeconds } from '@/utils/formatTime'
|
||||||
|
|
||||||
defineOptions({ name: 'ImVoiceRecorder' })
|
defineOptions({ name: 'ImVoiceRecorder' })
|
||||||
|
|
@ -56,6 +56,8 @@ const emit = defineEmits<{
|
||||||
send: [payload: { blob: Blob; duration: number }] // 录制完成:返回录音 Blob 和时长(秒)
|
send: [payload: { blob: Blob; duration: number }] // 录制完成:返回录音 Blob 和时长(秒)
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
const visible = computed({
|
const visible = computed({
|
||||||
get: () => props.modelValue,
|
get: () => props.modelValue,
|
||||||
set: (v) => emit('update:modelValue', v)
|
set: (v) => emit('update:modelValue', v)
|
||||||
|
|
@ -76,13 +78,13 @@ watch(visible, (v) => {
|
||||||
|
|
||||||
async function startRecord() {
|
async function startRecord() {
|
||||||
if (!navigator.mediaDevices?.getUserMedia) {
|
if (!navigator.mediaDevices?.getUserMedia) {
|
||||||
ElMessage.error('当前浏览器不支持录音(需要 HTTPS 或 localhost)')
|
message.error('当前浏览器不支持录音(需要 HTTPS 或 localhost)')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true })
|
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ElMessage.error('无法获取麦克风权限')
|
message.error('无法获取麦克风权限')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
audioChunks = []
|
audioChunks = []
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
import Icon from '@/components/Icon/src/Icon.vue'
|
import Icon from '@/components/Icon/src/Icon.vue'
|
||||||
|
|
@ -338,6 +338,7 @@ const userStore = useUserStore()
|
||||||
const conversationStore = useConversationStore()
|
const conversationStore = useConversationStore()
|
||||||
const groupStore = useGroupStore()
|
const groupStore = useGroupStore()
|
||||||
const { convertPrivateMessage, convertGroupMessage } = useMessagePuller()
|
const { convertPrivateMessage, convertGroupMessage } = useMessagePuller()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
const visible = computed({
|
const visible = computed({
|
||||||
get: () => props.modelValue,
|
get: () => props.modelValue,
|
||||||
|
|
@ -568,7 +569,7 @@ async function loadEarlier() {
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[IM] 加载更早历史消息失败', error)
|
console.error('[IM] 加载更早历史消息失败', error)
|
||||||
ElMessage.error('加载历史消息失败')
|
message.error('加载历史消息失败')
|
||||||
} finally {
|
} finally {
|
||||||
loadingMore.value = false
|
loadingMore.value = false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,9 +211,8 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||||
import { ElMessageBox } from 'element-plus'
|
|
||||||
|
|
||||||
import Icon from '@/components/Icon/src/Icon.vue'
|
import Icon from '@/components/Icon/src/Icon.vue'
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ImMessageType,
|
ImMessageType,
|
||||||
|
|
@ -254,6 +253,8 @@ const conversationStore = useConversationStore()
|
||||||
const groupStore = useGroupStore()
|
const groupStore = useGroupStore()
|
||||||
const uiStore = useImUiStore()
|
const uiStore = useImUiStore()
|
||||||
const { recall, sendRaw } = useMessageSender()
|
const { recall, sendRaw } = useMessageSender()
|
||||||
|
// 仅用 confirm,避免 message 跟 props.message 同名冲突(vue/no-dupe-keys)
|
||||||
|
const { confirm: confirmDialog } = useMessage()
|
||||||
|
|
||||||
/** 是否已撤回:pull / WS 两路都会调 recallMessage 把原消息更新为 type=RECALL,渲染只需识别 type */
|
/** 是否已撤回:pull / WS 两路都会调 recallMessage 把原消息更新为 type=RECALL,渲染只需识别 type */
|
||||||
const isRecall = computed(() => props.message.type === ImMessageType.RECALL)
|
const isRecall = computed(() => props.message.type === ImMessageType.RECALL)
|
||||||
|
|
@ -527,7 +528,7 @@ async function handleContextMenu(e: MouseEvent) {
|
||||||
*/
|
*/
|
||||||
async function handleRecall() {
|
async function handleRecall() {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要撤回这条消息吗?', '撤回消息', { type: 'warning' })
|
await confirmDialog('确定要撤回这条消息吗?', '撤回消息')
|
||||||
await recall(props.message)
|
await recall(props.message)
|
||||||
} catch {
|
} catch {
|
||||||
// ElMessageBox 在用户点取消时会 reject,吃掉即可
|
// ElMessageBox 在用户点取消时会 reject,吃掉即可
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue