From 787ccc59ba89bacc075562a161ecf02bc76ebadc Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 24 七月 2026 17:15:53 +0800
Subject: [PATCH] 银川 1.采购申请添加入库状态查询条件

---
 src/views/im/home/pages/conversation/components/conversation/conversation-item.vue |  330 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 330 insertions(+), 0 deletions(-)

diff --git a/src/views/im/home/pages/conversation/components/conversation/conversation-item.vue b/src/views/im/home/pages/conversation/components/conversation/conversation-item.vue
new file mode 100644
index 0000000..c7b1c51
--- /dev/null
+++ b/src/views/im/home/pages/conversation/components/conversation/conversation-item.vue
@@ -0,0 +1,330 @@
+<script lang="ts" setup>
+import type { Conversation } from '../../../../types'
+
+import { computed } from 'vue'
+
+import { confirm } from '#/packages/effects/common-ui/src'
+import { IconifyIcon as Icon } from '#/packages/icons/src'
+
+import { Tag } from 'ant-design-vue'
+
+import { buildRecallTip } from '#/views/im/utils/conversation'
+import { formatConversationTime } from '#/views/im/utils/time'
+import { getSenderDisplayName } from '#/views/im/utils/user'
+
+import { ImContentType, ImConversationType, isNormalMessage } from '../../../../../utils/constants'
+import { GroupAvatar } from '../../../../components/group'
+import { UserAvatar } from '../../../../components/user'
+import { useConversationStore } from '../../../../store/conversationStore'
+import { useFriendStore } from '../../../../store/friendStore'
+import { useGroupRequestStore } from '../../../../store/groupRequestStore'
+import { useGroupStore } from '../../../../store/groupStore'
+import { useImUiStore } from '../../../../store/uiStore'
+
+defineOptions({ name: 'ImConversationItem' })
+
+// 鍛ㄤ腑鏂囧悕锛坉ayjs 鐨� day() 杩斿洖 0-6锛�0=鍛ㄦ棩锛夛紱椤圭洰娌″叏灞�瑁� dayjs/locale/zh-cn锛屾湰鍦版槧灏勯伩鍏嶅紩鍓綔鐢�
+const props = defineProps<{
+  conversation: Conversation
+}>()
+
+const conversationStore = useConversationStore()
+const friendStore = useFriendStore()
+const groupStore = useGroupStore()
+const groupRequestStore = useGroupRequestStore()
+const uiStore = useImUiStore()
+
+const isActive = computed(
+  () =>
+    conversationStore.activeConversation?.targetId === props.conversation.targetId &&
+    conversationStore.activeConversation?.type === props.conversation.type
+)
+
+/**
+ * 褰撳墠浼氳瘽鐨勮崏绋垮揩鐓э細瀛樺湪鏃跺垪琛ㄦ樉绀� [鑽夌] 鍓嶇紑 + 鏂囨湰锛岀洊鎺� sender 鍓嶇紑鍜� @鎴� 绾㈠瓧
+ * 褰撳墠鎵撳紑鐨勪細璇濅笉灞曠ず鑽夌锛涜緭鍏ュ唴瀹瑰凡缁忓湪缂栬緫鍣ㄩ噷鍙锛屽垪琛ㄥ啀鏄剧ず [鑽夌] 鍙嶈�屽啑浣�
+ */
+const draft = computed(() => {
+  if (isActive.value) {
+    return undefined
+  }
+  return conversationStore.getConversationDraft(props.conversation)
+})
+
+const isGroup = computed(() => props.conversation.type === ImConversationType.GROUP)
+
+/** 鏈�鍚庝竴鏉℃秷鎭彂閫佽�呯殑灞曠ず鍚嶏細瀹炴椂绠� + 蹇収 fallback锛坓etSenderDisplayName 绠椾笉鍑烘椂鍏滃簳锛� */
+const lastSenderDisplayName = computed(() => {
+  const senderId = props.conversation.lastSenderId
+  if (!senderId) {
+    return ''
+  }
+  return getSenderDisplayName(
+    senderId,
+    props.conversation.type,
+    props.conversation.targetId,
+    props.conversation.lastSenderDisplayName
+  )
+})
+
+/** 缇よ亰 + 鏈夋渶鍚庡彂閫佽�� + 鏈�鍚庝竴鏉℃槸鏅�氭秷鎭椂锛屾樉绀哄彂閫佽�呭墠缂�锛團RIEND_* / GROUP_* / RECALL / 鑽夌鎬佷笉甯﹀墠缂�锛� */
+const showSendName = computed(() => {
+  if (draft.value) {
+    return false
+  }
+  if (!isGroup.value) {
+    return false
+  }
+  if (!props.conversation.lastSenderId) {
+    return false
+  }
+  const lastType = props.conversation.lastMessageType
+  return lastType != null && isNormalMessage(lastType)
+})
+
+/** 鍒楄〃灞曠ず鏂囨锛氳崏绋夸紭鍏堬紙瀵归綈寰俊 PC锛氭湁鑽夌鏃剁洊鎺夋渶鍚庝竴鏉¢瑙堬級鈫� 鎾ゅ洖瀹炴椂绠� 鈫� lastContent 鍏滃簳 */
+const lastContentDisplay = computed(() => {
+  if (draft.value) {
+    return draft.value.plain
+  }
+  if (
+    props.conversation.lastMessageType === ImContentType.RECALL &&
+    props.conversation.lastSenderId != null
+  ) {
+    return buildRecallTip(
+      props.conversation.lastSenderId,
+      !!props.conversation.lastSelfSend,
+      props.conversation.type,
+      props.conversation.targetId,
+      props.conversation.lastSenderDisplayName
+    )
+  }
+  return props.conversation.lastContent
+})
+
+/** 浼氳瘽鍒楄〃 "[鑽夌]" / "@ 鎴�" / "@ 鍏ㄤ綋鎴愬憳" 绾㈠瓧鎻愮ず锛涜崏绋夸紭鍏堬紙瀵归綈寰俊 PC锛� */
+const atText = computed(() => {
+  if (draft.value) {
+    return '[鑽夌]'
+  }
+  if (props.conversation.atMe) {
+    return '[鏈変汉@鎴慮'
+  }
+  if (props.conversation.atAll) {
+    return '[@鍏ㄤ綋鎴愬憳]'
+  }
+  return ''
+})
+
+/** 鍏嶆墦鎵颁細璇濇湭璇绘潯鏁版枃妗� */
+const mutedUnreadText = computed(() => {
+  if (!props.conversation.silent || props.conversation.unreadCount <= 0) {
+    return ''
+  }
+  const count = props.conversation.unreadCount > 99 ? '99+' : props.conversation.unreadCount
+  return `[${count}鏉`
+})
+
+/** 缇よ亰鏈鐞嗗姞缇ょ敵璇风孩瀛楀墠缂�锛泂tore 宸茬粡鎸夈�屾垜绠$悊鐨勭兢銆嶈繃婊よ繃锛宑ount > 0 鍗冲彲鏄剧ず */
+const requestText = computed(() => {
+  if (!isGroup.value) {
+    return ''
+  }
+  const count = groupRequestStore.getUnhandledGroupRequestCountMap.get(props.conversation.targetId) ?? 0
+  return count > 0 ? `[${count}鏉¤繘缇ょ敵璇穄` : ''
+})
+
+/** 鐐瑰嚮鍒囦細璇� */
+function handleClick() {
+  conversationStore.setActiveConversation(props.conversation)
+}
+
+/** 鍒囨崲缃《 */
+function handleTop() {
+  conversationStore.setConversationTop(
+    props.conversation.type,
+    props.conversation.targetId,
+    !props.conversation.top
+  )
+}
+
+/** 鍒囨崲鍏嶆墦鎵帮細涔愯 UI锛堝厛鏈湴鍒囨崲锛岃彍鍗曠珛鍗冲叧锛涘悗绔け璐ュ洖婊� conversation 鐘舵�侊級 */
+function handleMuted() {
+  const next = !props.conversation.silent
+  const { type, targetId } = props.conversation
+  conversationStore.setConversationSilent(type, targetId, next)
+  const sync =
+    type === ImConversationType.PRIVATE
+      ? friendStore.setFriendSilent(targetId, next)
+      : groupStore.setGroupSilent(targetId, next)
+  sync.catch((error) => {
+    console.error('[IM] 鍒囨崲鍏嶆墦鎵板け璐�', error)
+    conversationStore.setConversationSilent(type, targetId, !next)
+  })
+}
+
+/** 鍒犻櫎浼氳瘽锛氫簩娆$‘璁ゅ悗杞垹 */
+async function handleDelete() {
+  try {
+    await confirm(`纭畾鍒犻櫎涓庛��${props.conversation.name}銆嶇殑浼氳瘽鍚楋紵`, '鍒犻櫎浼氳瘽')
+    conversationStore.removeConversation(props.conversation.type, props.conversation.targetId)
+  } catch {}
+}
+
+/** 鍙抽敭鑿滃崟锛氱疆椤� / 鍏嶆墦鎵� / 鍒犻櫎 */
+function handleContextMenu(e: MouseEvent) {
+  uiStore.openContextMenu(
+    { x: e.clientX, y: e.clientY },
+    [
+      { key: 'TOP', name: props.conversation.top ? '鍙栨秷缃《' : '缃《' },
+      { key: 'MUTED', name: props.conversation.silent ? '鍏佽娑堟伅閫氱煡' : '娑堟伅鍏嶆墦鎵�' },
+      { key: 'DELETE', name: '鍒犻櫎', divided: true, danger: true }
+    ],
+    (item) => {
+      switch (item.key) {
+      case 'DELETE': {
+        void handleDelete()
+
+      break;
+      }
+      case 'MUTED': {
+        handleMuted()
+
+      break;
+      }
+      case 'TOP': {
+        handleTop()
+
+      break;
+      }
+      // No default
+      }
+    }
+  )
+}
+
+</script>
+
+<template>
+  <div
+    class="relative flex items-center gap-2.5 px-4 py-3 cursor-pointer transition-colors hover:bg-[var(--ant-color-fill)]"
+    :class="{ '!bg-[#d9ecff] dark:!bg-[var(--ant-color-primary-bg-hover)]': isActive }"
+    :data-conversation-key="`${conversation.type}-${conversation.targetId}`"
+    @click="handleClick"
+    @contextmenu.prevent="handleContextMenu"
+  >
+    <!-- 澶村儚 + 鏈鎻愮ず -->
+    <div class="relative">
+      <GroupAvatar
+        v-if="isGroup"
+        :group-id="conversation.targetId"
+        :url="conversation.avatar"
+        :name="conversation.name"
+        :size="40"
+      />
+      <UserAvatar
+        v-else
+        :url="conversation.avatar"
+        :name="conversation.name"
+        :size="40"
+        :clickable="false"
+      />
+      <!-- 鏁板瓧寰芥爣锛氶潪鍏嶆墦鎵颁笖鏈夋湭璇绘椂鏄剧ず鍏蜂綋鏉℃暟 -->
+      <span
+        v-show="!conversation.silent && conversation.unreadCount > 0"
+        class="absolute -top-1.5 -right-1.5 min-w-[18px] h-[18px] px-1.5 text-11px leading-[18px] text-white text-center bg-[#f56c6c] border border-solid border-white dark:border-[var(--ant-color-bg-container)] rounded-full box-border whitespace-nowrap"
+      >
+        {{ conversation.unreadCount > 99 ? '99+' : conversation.unreadCount }}
+      </span>
+      <!-- 灏忕孩鐐癸細鍏嶆墦鎵颁笖鏈夋湭璇绘椂鎻愮ず瀛樺湪鏂版秷鎭� -->
+      <span
+        v-show="conversation.silent && conversation.unreadCount > 0"
+        class="absolute -top-1 -right-1 w-2.5 h-2.5 bg-[#f56c6c] border border-solid border-white dark:border-[var(--ant-color-bg-container)] rounded-full box-border"
+      ></span>
+    </div>
+
+    <div class="flex-1 min-w-0">
+      <div class="flex items-center justify-between">
+        <span class="flex flex-1 items-center gap-1 min-w-0">
+          <span class="overflow-hidden text-sm truncate text-[var(--ant-color-text)]">
+            {{ conversation.name }}
+          </span>
+          <Tag
+            v-if="isGroup"
+            type="primary"
+            size="small"
+            class="conversation-item__tag flex-shrink-0 !h-[18px] !px-1 !leading-4"
+          >
+            缇�
+          </Tag>
+        </span>
+        <span class="flex-shrink-0 ml-1 text-12px text-[var(--ant-color-text-secondary)]">
+          {{ formatConversationTime(conversation.lastSendTime) }}
+        </span>
+      </div>
+      <div class="flex items-center mt-1 leading-5">
+        <!-- 杩涚兢鐢宠绾㈠瓧鍓嶇紑锛氱兢涓� / 绠$悊鍛樼湅鍒拌嚜宸辩鐞嗙殑缇や笅杩樻湁鏈鐞嗙敵璇锋椂鏄剧ず -->
+        <span
+          v-if="requestText"
+          class="conversation-item__prefix flex-shrink overflow-hidden text-12px text-[#c70b0b] truncate whitespace-nowrap"
+        >
+          {{ requestText }}
+        </span>
+        <!-- @绾㈠瓧鎻愮ず锛歛tMe 浼樺厛浜� atAll -->
+        <span
+          v-if="atText"
+          class="conversation-item__prefix flex-shrink overflow-hidden text-12px text-[#c70b0b] truncate whitespace-nowrap"
+        >
+          {{ atText }}
+        </span>
+        <!-- 鍏嶆墦鎵版湭璇绘潯鏁� -->
+        <span
+          v-if="mutedUnreadText"
+          class="flex-shrink-0 mr-1 text-12px text-[var(--ant-color-text-secondary)] whitespace-nowrap"
+        >
+          {{ mutedUnreadText }}
+        </span>
+        <!-- 缇よ亰鏈�鍚庝竴鏉″彂閫佽�呭墠缂�锛氭寜 lastSenderId + 褰撳墠浼氳瘽涓婁笅鏂囧疄鏃剁畻鍚嶅瓧 -->
+        <span
+          v-if="showSendName"
+          class="conversation-item__sender flex-shrink overflow-hidden text-12px text-[var(--ant-color-text-secondary)] truncate whitespace-nowrap"
+        >
+          {{ lastSenderDisplayName }}:&nbsp;
+        </span>
+        <span
+          class="flex-1 min-w-0 overflow-hidden text-12px truncate text-[var(--ant-color-text-secondary)]"
+        >
+          {{ lastContentDisplay }}
+        </span>
+        <!-- 鍏嶆墦鎵板浘鏍� -->
+        <Icon
+          v-if="conversation.silent"
+          icon="mdi:bell-off-outline"
+          :size="14"
+          class="conversation-item__silent flex-shrink-0 ml-1 text-[var(--ant-color-text-disabled)]"
+          title="娑堟伅鍏嶆墦鎵�"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<style scoped>
+/* 娑堟帀 el-tag 鍒囦細璇濇椂 active 搴曡壊鍙樺寲鐨勬笎鍙橈紙鐪嬭捣鏉ュ儚闂儊锛夛紱 :deep 绌块�� el-tag 鑷韩鏍峰紡 */
+.conversation-item__tag {
+  transition: none !important;
+}
+
+/* el-icon 鐨勫叏灞� color:var(--color) 鍦ㄦ殫鑹叉ā寮忎笅浼氭覆鏌撴垚鐧借壊锛岃繖閲岀敤 :deep + !important 閿佸畾 */
+.conversation-item__silent :deep(svg) {
+  fill: currentColor !important;
+}
+
+.conversation-item__prefix {
+  max-width: 45%;
+}
+
+.conversation-item__sender {
+  max-width: 50%;
+}
+</style>

--
Gitblit v1.9.3