From 27cd042df9aca0383a49f3514bc21958dd890912 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 29 六月 2026 15:42:23 +0800
Subject: [PATCH] 银川 1.联调产品维护页面 2.添加IM即时通讯模块
---
src/views/im/home/components/context-menu.vue | 99 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 99 insertions(+), 0 deletions(-)
diff --git a/src/views/im/home/components/context-menu.vue b/src/views/im/home/components/context-menu.vue
new file mode 100644
index 0000000..df364c9
--- /dev/null
+++ b/src/views/im/home/components/context-menu.vue
@@ -0,0 +1,99 @@
+<script lang="ts" setup>
+import { computed } from 'vue'
+
+import { IconifyIcon as Icon } from '#/packages/icons/src'
+
+import { useImUiStore } from '../store/uiStore'
+
+defineOptions({ name: 'ImContextMenu' })
+
+const uiStore = useImUiStore()
+const contextMenu = computed(() => uiStore.contextMenu)
+
+/**
+ * 璁$畻鑿滃崟瀹為檯娓叉煋鍧愭爣锛氶潬杩戣鍙e彸 / 涓嬭竟缂樻椂鍥炲脊锛岄伩鍏嶈彍鍗曡瑁佸壀
+ *
+ * itemHeight / menuWidth 鏄拰妯℃澘閲� px-4 py-2 + text-13px / min-w-30 閰嶅鐨勫疄闄呭昂瀵革紱
+ * dividerHeight = 9px锛坢y-1 涓婁笅鍚� 4 + 1px border锛夛紝浠呴潪棣栭」鐨� divided 璁″叆锛�
+ * menuHeight 棰濆鍔� 8 鏄灞� py-1 鐨勪笂涓� padding 涔嬪拰锛�4px 脳 2锛�
+ */
+const adjustedPosition = computed(() => {
+ const items = contextMenu.value.items
+ const itemHeight = 34
+ const dividerCount = items.filter((it, i) => it.divided && i > 0).length
+ const menuHeight = items.length * itemHeight + dividerCount * 9 + 8
+ const menuWidth = 120
+ let x = contextMenu.value.position.x
+ let y = contextMenu.value.position.y
+ // SSR 鍏滃簳锛歸indow 涓嶅彲鐢ㄦ椂鐩存帴杩斿洖鍘熷鍧愭爣
+ if (typeof window !== 'undefined') {
+ if (y + menuHeight > window.innerHeight) {
+ y = window.innerHeight - menuHeight
+ }
+ if (x + menuWidth > window.innerWidth) {
+ x = window.innerWidth - menuWidth
+ }
+ }
+ // 瑙嗗彛寰堝皬 / 鑿滃崟椤瑰緢澶氭椂涓婇潰鍑忔硶浼氱畻鍑鸿礋鍊硷紝鎶婅彍鍗曢《 / 宸﹁竟鎺ㄥ埌 0 鍏滃簳
+ return { x: Math.max(0, x), y: Math.max(0, y) }
+})
+
+type MenuItem = (typeof contextMenu.value.items)[number]
+
+/** 閫変腑鑿滃崟椤癸細disabled 椤瑰拷鐣ワ紱姝e父椤硅皟 onSelect 鍥炶皟鍚庡叧闂彍鍗� */
+function handleSelect(item: MenuItem) {
+ if (item.disabled) {
+ return
+ }
+ uiStore.contextMenu.onSelect?.(item)
+ uiStore.closeContextMenu()
+}
+
+/** 鍏抽棴鑿滃崟锛氱偣閬僵 / 鍦ㄩ伄缃╀笂鍐嶆鍙抽敭閮戒細瑙﹀彂 */
+function handleClose() {
+ uiStore.closeContextMenu()
+}
+</script>
+
+<template>
+ <!--
+ 閫氱敤鍙抽敭鑿滃崟
+ 鐢� useImUiStore.openContextMenu(position, items, onSelect) 瑙﹀彂鍏ㄥ眬鍗曚緥灞曠ず
+ 璋冪敤鏂瑰湪 @contextmenu.prevent 浜嬩欢閲岃皟 openContextMenu 鍗冲彲锛屼笉闇�瑕佽嚜宸辨寕缁勪欢
+ -->
+ <teleport to="body">
+ <div
+ v-if="contextMenu.show"
+ class="fixed inset-0 z-9999"
+ @click.stop="handleClose"
+ @contextmenu.prevent="handleClose"
+ >
+ <div
+ class="fixed min-w-30 py-1 bg-[var(--ant-color-bg-elevated)] rounded-md shadow-lg"
+ :style="{ left: `${adjustedPosition.x }px`, top: `${adjustedPosition.y }px` }"
+ >
+ <template v-for="(item, index) in contextMenu.items" :key="item.key">
+ <!-- divided 椤逛笂鏂规彃涓�鏉″垎鍓茬嚎锛堥椤硅烦杩囷紝閬垮厤绌虹櫧锛� -->
+ <div
+ v-if="item.divided && index > 0"
+ class="my-1 mx-2 h-[1px] bg-[var(--ant-color-border-secondary)]"
+ ></div>
+ <div
+ class="flex gap-2 items-center px-4 py-2 text-13px text-left cursor-pointer transition-colors hover:bg-[var(--ant-color-fill)]"
+ :class="[
+ item.disabled
+ ? '!text-[var(--ant-color-text-disabled)] cursor-not-allowed hover:!bg-transparent'
+ : item.danger
+ ? 'text-[#f56c6c]'
+ : 'text-[var(--ant-color-text)]'
+ ]"
+ @click.stop="handleSelect(item)"
+ >
+ <Icon v-if="item.icon" :icon="item.icon" :size="14" />
+ <span>{{ item.name }}</span>
+ </div>
+ </template>
+ </div>
+ </div>
+ </teleport>
+</template>
--
Gitblit v1.9.3