feat(im): 修一批 L 危:window.open 加 noopener、@ 浮层箭头方向跟随定位、置顶展开切群重置、加黑名单取消静默、菜单负坐标兜底、群选择回显跨页补查

pull/881/head
YunaiV 2026-05-21 14:25:21 +08:00
parent 3949e0c89f
commit 1015423431
7 changed files with 46 additions and 15 deletions

View File

@ -76,7 +76,8 @@ const adjustedPosition = computed(() => {
x = window.innerWidth - menuWidth x = window.innerWidth - menuWidth
} }
} }
return { x, y } // / / 0
return { x: Math.max(0, x), y: Math.max(0, y) }
}) })
type MenuItem = (typeof contextMenu.value.items)[number] type MenuItem = (typeof contextMenu.value.items)[number]

View File

@ -386,7 +386,11 @@ async function handleBlock() {
return return
} }
const target = props.user const target = props.user
await message.confirm(`确定将「${target.nickname || ''}」加入黑名单吗?`, '加入黑名单') try {
await message.confirm(`确定将「${target.nickname || ''}」加入黑名单吗?`, '加入黑名单')
} catch {
return
}
await friendStore.blockFriend(target.id) await friendStore.blockFriend(target.id)
message.success('已加入黑名单') message.success('已加入黑名单')
} }

View File

@ -52,8 +52,11 @@
/> />
</el-scrollbar> </el-scrollbar>
<!-- 底部三角指针旋转 45° 的方块半露出底边指向输入区里的 @ 字符 --> <!-- 三角指针picker @ 下方position.top 锚定 箭头朝上贴顶picker @ 上方position.bottom 锚定 箭头朝下贴底 -->
<div class="absolute left-4 -bottom-1.5 w-3 h-3 rotate-45 bg-[var(--el-bg-color)]"></div> <div
class="absolute left-4 w-3 h-3 rotate-45 bg-[var(--el-bg-color)]"
:class="position.top != null ? '-top-1.5' : '-bottom-1.5'"
></div>
</div> </div>
</template> </template>

View File

@ -60,7 +60,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from 'vue' import { computed, ref, watch } from 'vue'
import Icon from '@/components/Icon/src/Icon.vue' import Icon from '@/components/Icon/src/Icon.vue'
import { useMessage } from '@/hooks/web/useMessage' import { useMessage } from '@/hooks/web/useMessage'
import { ImConversationType, ImGroupMemberRole } from '@/views/im/utils/constants' import { ImConversationType, ImGroupMemberRole } from '@/views/im/utils/constants'
@ -93,6 +93,15 @@ const group = computed(() => groupStore.getGroup(props.groupId))
const expanded = ref(false) const expanded = ref(false)
const removingId = ref<number | null>(null) const removingId = ref<number | null>(null)
// / ref groupId""""
watch(
() => props.groupId,
() => {
expanded.value = false
removingId.value = null
}
)
/** 当前群置顶消息列表(直接走 group.value跟随响应式 */ /** 当前群置顶消息列表(直接走 group.value跟随响应式 */
const pinnedMessages = computed<Message[]>(() => group.value?.pinnedMessages ?? []) const pinnedMessages = computed<Message[]>(() => group.value?.pinnedMessages ?? [])

View File

@ -322,7 +322,8 @@ function handleFileClick() {
if (isUploading.value || !filePayload.value?.url) { if (isUploading.value || !filePayload.value?.url) {
return return
} }
window.open(filePayload.value.url, '_blank') // noopener,noreferrer window.opener Tabnabbing
window.open(filePayload.value.url, '_blank', 'noopener,noreferrer')
} }
/** 语音点击:托管给 useVoicePlayer 全局互斥播放,新点的语音会停掉旧的 */ /** 语音点击:托管给 useVoicePlayer 全局互斥播放,新点的语音会停掉旧的 */

View File

@ -198,14 +198,14 @@ const getList = async () => {
list.value = data.list list.value = data.list
total.value = data.total total.value = data.total
await nextTick() await nextTick()
applyPreSelection() await applyPreSelection()
} finally { } finally {
loading.value = false loading.value = false
} }
} }
/** 恢复预选状态(当前页可见范围内 */ /** 恢复预选状态:当前页命中直接复用 row否则单选时调单条详情接口补齐防已选群不在第一页时确认报"请选择" */
const applyPreSelection = () => { const applyPreSelection = async () => {
if (preSelectedIds.value.length === 0) { if (preSelectedIds.value.length === 0) {
return return
} }
@ -219,12 +219,24 @@ const applyPreSelection = () => {
table.toggleRowSelection(row, true) table.toggleRowSelection(row, true)
} }
}) })
} else { return
const match = list.value.find((row) => preSelectedIds.value.includes(row.id)) }
if (match) { const targetId = preSelectedIds.value[0]
selectedRadioId.value = match.id const match = list.value.find((row) => row.id === targetId)
currentRadioRow.value = match if (match) {
selectedRadioId.value = match.id
currentRadioRow.value = match
return
}
// currentRadioRow id + confirmSelect
try {
const detail = await ManagerGroupApi.getManagerGroup(targetId)
if (detail) {
selectedRadioId.value = detail.id
currentRadioRow.value = detail
} }
} catch (e) {
console.warn('[GroupSelectDialog] 预选群详情拉取失败', { targetId }, e)
} }
} }

View File

@ -227,7 +227,8 @@ const mergePreviewLines = computed(() => {
function openVideo() { function openVideo() {
const url = videoPayload.value?.url const url = videoPayload.value?.url
if (url) { if (url) {
window.open(url, '_blank') // noopener,noreferrer window.opener Tabnabbing
window.open(url, '_blank', 'noopener,noreferrer')
} }
} }