|
|
@@ -36,11 +36,12 @@
|
|
|
<component :is="cat.icon" />
|
|
|
</el-icon>
|
|
|
<span class="side-text">{{ cat.title }}</span>
|
|
|
+ <el-badge v-if="cat.unread > 0" :value="handleReadCount(cat.unread)" class="side-badge" />
|
|
|
</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 右侧:通知列表 -->
|
|
|
+ <!-- 右侧:通知列表(系统通知/订单提醒:卡片式;互动:头像+发送者+内容+日期) -->
|
|
|
<div v-if="activeTab === 'notice'" class="drawer-main-wrap">
|
|
|
<div class="drawer-main">
|
|
|
<div v-if="currentLoading" class="empty-tip">
|
|
|
@@ -50,27 +51,58 @@
|
|
|
<span style="margin-left: 8px">加载中...</span>
|
|
|
</div>
|
|
|
<template v-else>
|
|
|
- <div
|
|
|
- v-for="(item, index) in currentList"
|
|
|
- :key="item.id + '_' + index"
|
|
|
- class="notice-card"
|
|
|
- :class="{ unread: item.unread }"
|
|
|
- >
|
|
|
- <div class="card-row">
|
|
|
- <span class="card-title">
|
|
|
- {{ item.title }}
|
|
|
- <span v-if="item.unread" class="unread-dot" />
|
|
|
- </span>
|
|
|
- <span class="card-date">{{ item.date }}</span>
|
|
|
- </div>
|
|
|
- <div class="card-content">
|
|
|
- {{ item.content }}
|
|
|
+ <!-- 系统通知、订单提醒:卡片式 -->
|
|
|
+ <template v-if="activeCategory !== 'related'">
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in currentList"
|
|
|
+ :key="item.id + '_' + index"
|
|
|
+ class="notice-card"
|
|
|
+ :class="{ unread: item.unread }"
|
|
|
+ >
|
|
|
+ <div class="card-row">
|
|
|
+ <span class="card-title">
|
|
|
+ {{ item.title }}
|
|
|
+ <span v-if="item.unread" class="unread-dot" />
|
|
|
+ </span>
|
|
|
+ <span class="card-date">{{ item.date }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="card-content">
|
|
|
+ {{ processContent(item) }}
|
|
|
+ </div>
|
|
|
+ <div class="card-actions">
|
|
|
+ <el-button size="small" @click="handleViewDetail(item)"> 查看详情 </el-button>
|
|
|
+ <!-- <el-button size="small" @click="handleDelete(item, index)"> 删除 </el-button> -->
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="card-actions">
|
|
|
- <el-button size="small" @click="handleViewDetail(item)"> 查看详情 </el-button>
|
|
|
- <el-button size="small" @click="handleDelete(item, index)"> 删除 </el-button>
|
|
|
+ </template>
|
|
|
+ <!-- 互动:头像+发送者+内容+日期+删除(与商家端 inform 列表一致) -->
|
|
|
+ <template v-else>
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in currentList"
|
|
|
+ :key="item.id + '_' + index"
|
|
|
+ class="message-card"
|
|
|
+ :class="{ unread: item.unread }"
|
|
|
+ >
|
|
|
+ <div class="message-avatar">
|
|
|
+ <el-avatar :size="40" :src="item.userImage">
|
|
|
+ <el-icon><UserFilled /></el-icon>
|
|
|
+ </el-avatar>
|
|
|
+ <span v-if="item.unread" class="unread-dot message-unread-dot" />
|
|
|
+ </div>
|
|
|
+ <div class="message-body" @click="handleViewDetail(item)">
|
|
|
+ <div class="message-row">
|
|
|
+ <span class="message-sender">{{ item.userName || item.title || "未知" }}</span>
|
|
|
+ <span class="message-date">{{ item.date }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="message-content">
|
|
|
+ {{ processContent(item) }}
|
|
|
+ </div>
|
|
|
+ <!-- <div class="message-actions">
|
|
|
+ <el-button size="small" type="default" @click.stop="handleDelete(item, index)"> 删除 </el-button>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </template>
|
|
|
<div v-if="currentList.length === 0" class="empty-tip">暂无数据</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
@@ -97,8 +129,15 @@
|
|
|
</el-icon>
|
|
|
<span style="margin-left: 8px">加载中...</span>
|
|
|
</div>
|
|
|
+ <!-- @click="handleMessageItemClick(item)" -->
|
|
|
<template v-else>
|
|
|
- <div v-for="(item, index) in currentMessageList" :key="item.id + '_' + index" class="message-card">
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in currentMessageList"
|
|
|
+ :key="item.id + '_' + index"
|
|
|
+ class="message-card message-card-clickable"
|
|
|
+ :class="{ unread: item.unread }"
|
|
|
+ @click="handleMessageItemClick(item)"
|
|
|
+ >
|
|
|
<div class="message-avatar">
|
|
|
<el-avatar :size="40" :src="item.avatar">
|
|
|
<el-icon><UserFilled /></el-icon>
|
|
|
@@ -109,11 +148,16 @@
|
|
|
<span class="message-sender">{{ item.senderName }}</span>
|
|
|
<span class="message-date">{{ item.date }}</span>
|
|
|
</div>
|
|
|
- <div class="message-content">
|
|
|
- {{ item.content }}
|
|
|
- </div>
|
|
|
- <div class="message-actions">
|
|
|
- <el-button size="small" type="default" @click="handleMessageDelete(item, index)"> 删除 </el-button>
|
|
|
+ <div class="message-content-row">
|
|
|
+ <span class="message-content">{{ processContent(item) }}</span>
|
|
|
+ <div class="message-status">
|
|
|
+ <!-- 非免打扰:显示数字徽标 -->
|
|
|
+ <span v-if="item.isNotDisturb !== '1' && (item.notReadCount ?? 0) > 0" class="message-count">
|
|
|
+ {{ handleReadCount(item.notReadCount!) }}
|
|
|
+ </span>
|
|
|
+ <!-- 免打扰:显示小红点 -->
|
|
|
+ <span v-else-if="item.isNotDisturb === '1' && (item.notReadCount ?? 0) > 0" class="message-dot" />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -133,24 +177,33 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, computed, onMounted, watch } from "vue";
|
|
|
+import { ref, computed, onMounted, watch, markRaw } from "vue";
|
|
|
+import { useRouter } from "vue-router";
|
|
|
import { House, List, User, Loading, Message, UserFilled } from "@element-plus/icons-vue";
|
|
|
import { localGet } from "@/utils";
|
|
|
import {
|
|
|
getNoticeListForHeader,
|
|
|
readNoticeById,
|
|
|
getCountUnreadByType,
|
|
|
- getNoFriendMessage,
|
|
|
- getMessageList
|
|
|
+ getMessageList,
|
|
|
+ getStrangerMessageNum
|
|
|
} from "@/api/modules/headerNotice";
|
|
|
import type { NoFriendMessageItem } from "@/api/modules/headerNotice";
|
|
|
|
|
|
+const emit = defineEmits<{ (e: "close"): void }>();
|
|
|
+const router = useRouter();
|
|
|
+
|
|
|
interface NoticeItem {
|
|
|
id: string;
|
|
|
title: string;
|
|
|
content: string;
|
|
|
date: string;
|
|
|
unread: boolean;
|
|
|
+ /** 互动类可能有发送者与头像 */
|
|
|
+ userName?: string;
|
|
|
+ userImage?: string;
|
|
|
+ /** 类型,用于 processContent 展示 */
|
|
|
+ type?: string;
|
|
|
}
|
|
|
|
|
|
interface MessageItem {
|
|
|
@@ -159,7 +212,21 @@ interface MessageItem {
|
|
|
content: string;
|
|
|
date: string;
|
|
|
unread: boolean;
|
|
|
+ /** 未读数量,用于展示红点/数字 */
|
|
|
+ notReadCount?: number;
|
|
|
+ /** 免打扰:'0' 非免打扰显示数字,'1' 免打扰显示小红点(与商家端一致) */
|
|
|
+ isNotDisturb?: string;
|
|
|
avatar?: string;
|
|
|
+ /** 发送方 phoneId,用于跳转聊天页 */
|
|
|
+ phoneId?: string;
|
|
|
+ /** 发送方 id,用于跳转聊天页 */
|
|
|
+ senderId?: string;
|
|
|
+ /** 消息类型,用于 processContent 展示 */
|
|
|
+ type?: string;
|
|
|
+ /** 语音时长等,用于 getVoiceDuration */
|
|
|
+ voiceDuration?: number;
|
|
|
+ duration?: number;
|
|
|
+ [key: string]: any;
|
|
|
}
|
|
|
|
|
|
const activeTab = ref<"notice" | "message">("notice");
|
|
|
@@ -172,16 +239,17 @@ const noticeTypeByKey: Record<string, number> = {
|
|
|
order: 2,
|
|
|
related: 0
|
|
|
};
|
|
|
+// 与商家端一致:系统通知、订单提醒、互动(其余通知均为互动类别)。icon 用 markRaw 避免被转为响应式触发 Vue 警告
|
|
|
const noticeCategories = ref([
|
|
|
- { key: "system", title: "系统通知", icon: House, unread: 0 },
|
|
|
- { key: "order", title: "订单提醒", icon: List, unread: 0 },
|
|
|
- { key: "related", title: "与我相关", icon: User, unread: 0 }
|
|
|
+ { key: "system", title: "系统通知", icon: markRaw(House), unread: 0 },
|
|
|
+ { key: "order", title: "订单提醒", icon: markRaw(List), unread: 0 },
|
|
|
+ { key: "related", title: "互动", icon: markRaw(User), unread: 0 }
|
|
|
]);
|
|
|
|
|
|
// 消息 Tab 分类(如图:未关注人消息、消息列表)
|
|
|
const messageCategories = ref([
|
|
|
- { key: "unfollowed", title: "未关注人消息", icon: User, unread: 0 },
|
|
|
- { key: "messageList", title: "消息列表", icon: Message, unread: 0 }
|
|
|
+ { key: "unfollowed", title: "未关注人消息", icon: markRaw(User), unread: 0 },
|
|
|
+ { key: "messageList", title: "消息列表", icon: markRaw(Message), unread: 0 }
|
|
|
]);
|
|
|
|
|
|
const listByCategory = ref<Record<string, NoticeItem[]>>({
|
|
|
@@ -248,41 +316,75 @@ function switchMessageCategory(key: string) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 未关注人消息:/message/getNoFriendMessage,参数 receiverId
|
|
|
+// 未关注人消息:/message/getNoFriendMessage,参数 receiverId。映射与商家端 message-notices 一致
|
|
|
function mapNoFriendToMessageItem(item: NoFriendMessageItem): MessageItem {
|
|
|
const createdTime = item.createdTime ?? "";
|
|
|
const dateStr = createdTime.includes(" ") ? createdTime.split(" ")[0].replace(/-/g, "/") : createdTime.replace(/-/g, "/");
|
|
|
+ const notReadCount = item.notReadCount ?? (item.isRead === 0 ? 1 : 0);
|
|
|
return {
|
|
|
id: String(item.id ?? ""),
|
|
|
senderName: item.senderName ?? item.userName ?? "",
|
|
|
content: item.content ?? "",
|
|
|
date: dateStr,
|
|
|
unread: item.isRead === 0,
|
|
|
- avatar: item.userImage ?? item.senderImg ?? item.storeImg ?? undefined
|
|
|
+ notReadCount,
|
|
|
+ isNotDisturb: (item as any).isNotDisturb ?? "0",
|
|
|
+ avatar: item.userImage ?? item.senderImg ?? item.storeImg ?? undefined,
|
|
|
+ phoneId: (item as any).phoneId != null ? String((item as any).phoneId) : undefined,
|
|
|
+ senderId: item.senderId != null ? String(item.senderId) : undefined,
|
|
|
+ type: item.type,
|
|
|
+ voiceDuration: (item as any).voiceDuration ?? (item as any).duration,
|
|
|
+ duration: (item as any).duration
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-async function fetchNoFriendMessage() {
|
|
|
+// 未关注人消息未读数:使用 message/getStrangerMessageNum 接口,取 data.notReadCount
|
|
|
+async function fetchUnfollowedUnreadCount() {
|
|
|
const receiverId = getReceiverId();
|
|
|
if (!receiverId) {
|
|
|
- messageListByCategory.value.unfollowed = [];
|
|
|
const cat = messageCategories.value.find(c => c.key === "unfollowed");
|
|
|
if (cat) cat.unread = 0;
|
|
|
return;
|
|
|
}
|
|
|
+ try {
|
|
|
+ const res: any = await getStrangerMessageNum({ receiverId: "store_" + receiverId });
|
|
|
+ if (res?.mas == "暂无承载数据" || res?.msg == "暂无承载数据") {
|
|
|
+ const cat = messageCategories.value.find(c => c.key === "unfollowed");
|
|
|
+ if (cat) cat.unread = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const data = res?.data ?? res;
|
|
|
+ const notReadCount = data?.notReadCount ?? 0;
|
|
|
+ const cat = messageCategories.value.find(c => c.key === "unfollowed");
|
|
|
+ if (cat) cat.unread = Number(notReadCount) || 0;
|
|
|
+ } catch (e) {
|
|
|
+ const cat = messageCategories.value.find(c => c.key === "unfollowed");
|
|
|
+ if (cat) cat.unread = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 陌生人/未关注人消息列表:使用 message/getMessageList,friendType=2(与商家端 message-notFriend 一致)
|
|
|
+async function fetchNoFriendMessage() {
|
|
|
+ const receiverId = getReceiverId();
|
|
|
+ if (!receiverId) {
|
|
|
+ messageListByCategory.value.unfollowed = [];
|
|
|
+ await fetchUnfollowedUnreadCount();
|
|
|
+ return;
|
|
|
+ }
|
|
|
messageLoading.value = true;
|
|
|
try {
|
|
|
- const res: any = await getNoFriendMessage({ receiverId: "store_" + receiverId });
|
|
|
+ const res: any = await getMessageList({ receiverId: "store_" + receiverId, friendType: 2 });
|
|
|
const data = res?.data ?? res;
|
|
|
+ if (data?.msg == "暂无承载数据") {
|
|
|
+ messageListByCategory.value.unfollowed = [];
|
|
|
+ const cat = messageCategories.value.find(c => c.key === "unfollowed");
|
|
|
+ if (cat) cat.unread = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
const rawList = Array.isArray(data) ? data : data ? [data] : [];
|
|
|
const list: MessageItem[] = rawList.map((item: NoFriendMessageItem) => mapNoFriendToMessageItem(item));
|
|
|
messageListByCategory.value.unfollowed = list;
|
|
|
- const unreadTotal = rawList.reduce(
|
|
|
- (sum: number, item: NoFriendMessageItem) => sum + (item.notReadCount ?? (item.isRead === 0 ? 1 : 0)),
|
|
|
- 0
|
|
|
- );
|
|
|
- const cat = messageCategories.value.find(c => c.key === "unfollowed");
|
|
|
- if (cat) cat.unread = unreadTotal;
|
|
|
+ await fetchUnfollowedUnreadCount();
|
|
|
} catch (e) {
|
|
|
messageListByCategory.value.unfollowed = [];
|
|
|
const cat = messageCategories.value.find(c => c.key === "unfollowed");
|
|
|
@@ -292,7 +394,7 @@ async function fetchNoFriendMessage() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 消息列表:/message/getMessageList,参数 friendType 默认 0、receiverId,返回结构与 getNoFriendMessage 一致
|
|
|
+// 消息列表:/message/getMessageList,friendType=1 仅返回已关注/好友消息(不包含未关注人,与商家端一致)
|
|
|
async function fetchMessageList() {
|
|
|
const receiverId = getReceiverId();
|
|
|
if (!receiverId) {
|
|
|
@@ -303,7 +405,7 @@ async function fetchMessageList() {
|
|
|
}
|
|
|
messageLoading.value = true;
|
|
|
try {
|
|
|
- const res: any = await getMessageList({ receiverId: "store_" + receiverId, friendType: 0 });
|
|
|
+ const res: any = await getMessageList({ receiverId: "store_" + receiverId, friendType: 1 });
|
|
|
const data = res?.data ?? res;
|
|
|
const rawList = Array.isArray(data) ? data : data ? [data] : [];
|
|
|
const list: MessageItem[] = rawList.map((item: NoFriendMessageItem) => mapNoFriendToMessageItem(item));
|
|
|
@@ -328,6 +430,60 @@ function getReceiverId(): string {
|
|
|
return localGet("iphone") || localGet("geeker-user")?.userInfo?.phone || "";
|
|
|
}
|
|
|
|
|
|
+// 未读数量展示:超过 99 显示 99(与商家端 handleReadCount 一致)
|
|
|
+function handleReadCount(val: number): string {
|
|
|
+ if (Number(val) > 99) return "99";
|
|
|
+ return String(val);
|
|
|
+}
|
|
|
+
|
|
|
+// 点击消息列表项:关闭抽屉并跳转聊天页(与 storeDecoration 装修聊天一致,receiverId 用 phoneId)
|
|
|
+function handleMessageItemClick(item: MessageItem) {
|
|
|
+ const receiverId = item.phoneId ?? item.senderId;
|
|
|
+
|
|
|
+ if (!receiverId) return;
|
|
|
+ emit("close");
|
|
|
+ const params = new URLSearchParams({
|
|
|
+ receiverId: String(receiverId),
|
|
|
+ uName: encodeURIComponent(item.senderName || "用户"),
|
|
|
+ userImage: item.avatar ? encodeURIComponent(item.avatar) : ""
|
|
|
+ });
|
|
|
+ router.push(`/storeDecorationManagement/decorationChat?${params.toString()}`);
|
|
|
+}
|
|
|
+
|
|
|
+// 根据类型显示内容(与商家端一致)
|
|
|
+function getVoiceDuration(item: { voiceDuration?: number; duration?: number; [key: string]: any }): string {
|
|
|
+ const sec = item?.voiceDuration ?? item?.duration ?? 0;
|
|
|
+ return sec ? `${sec}` : "0";
|
|
|
+}
|
|
|
+function processContent(item: { type?: string; content?: string; [key: string]: any }): string {
|
|
|
+ switch (String(item.type ?? "")) {
|
|
|
+ case "1":
|
|
|
+ return item.content ?? "";
|
|
|
+ case "2":
|
|
|
+ return "[图片]";
|
|
|
+ case "3":
|
|
|
+ return "[分享]";
|
|
|
+ case "4":
|
|
|
+ return "[交易请求]";
|
|
|
+ case "5":
|
|
|
+ return "[签到]";
|
|
|
+ case "6":
|
|
|
+ return "[签到确认]";
|
|
|
+ case "8":
|
|
|
+ return "[视频]";
|
|
|
+ case "9":
|
|
|
+ return "[修改交易请求]";
|
|
|
+ case "10":
|
|
|
+ return "[定位共享]";
|
|
|
+ case "11":
|
|
|
+ return "[委托]";
|
|
|
+ case "13":
|
|
|
+ return "[语音]" + getVoiceDuration(item) + '"';
|
|
|
+ default:
|
|
|
+ return item.content ?? "";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 与原有通知页面一致的 context 解析
|
|
|
function parseContext(context: string | undefined): string {
|
|
|
if (!context) return "";
|
|
|
@@ -339,6 +495,15 @@ function parseContext(context: string | undefined): string {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 互动类内容:商家端 context 可能为 "类型|split|内容1|split|内容2",取第一段或解析 JSON
|
|
|
+function getInteractionContent(context: string | undefined): string {
|
|
|
+ if (!context) return "";
|
|
|
+ if (typeof context === "string" && context.includes("|split|")) {
|
|
|
+ return context.split("|split|")[0]?.trim() || context;
|
|
|
+ }
|
|
|
+ return parseContext(context);
|
|
|
+}
|
|
|
+
|
|
|
// 统一请求:/alienStorePlatform/notice/getNoticeList,noticeType 系统=1、订单提醒=2、与我相关=0,分页查询
|
|
|
async function fetchNoticeList(catKey: string) {
|
|
|
const receiverId = getReceiverId();
|
|
|
@@ -360,13 +525,25 @@ async function fetchNoticeList(catKey: string) {
|
|
|
const data = res?.data ?? res;
|
|
|
const records = data?.records ?? data?.list ?? [];
|
|
|
const total = data?.total ?? 0;
|
|
|
- const list: NoticeItem[] = records.map((item: any) => ({
|
|
|
- id: String(item.id),
|
|
|
- title: item.title ?? "",
|
|
|
- content: parseContext(item.context ?? item.content),
|
|
|
- date: item.createdTime ?? "",
|
|
|
- unread: !item.isRead
|
|
|
- }));
|
|
|
+ const isRelated = catKey === "related";
|
|
|
+ const list: NoticeItem[] = records.map((item: any) => {
|
|
|
+ const rawContext = item.context ?? item.content ?? "";
|
|
|
+ const content = isRelated ? getInteractionContent(rawContext) : parseContext(rawContext);
|
|
|
+ const dateRaw = item.createdTime ?? "";
|
|
|
+ const dateStr = dateRaw.includes(" ") ? dateRaw.split(" ")[0].replace(/-/g, "/") : dateRaw.replace(/-/g, "/");
|
|
|
+ return {
|
|
|
+ id: String(item.id),
|
|
|
+ title: item.title ?? "",
|
|
|
+ content,
|
|
|
+ date: dateStr,
|
|
|
+ unread: !item.isRead,
|
|
|
+ type: item.type,
|
|
|
+ ...(isRelated && {
|
|
|
+ userName: item.userName ?? item.senderName ?? item.title ?? "",
|
|
|
+ userImage: item.userImage ?? item.storeImg ?? item.senderImg
|
|
|
+ })
|
|
|
+ };
|
|
|
+ });
|
|
|
listByCategory.value[catKey] = list;
|
|
|
paginationByCategory.value[catKey].total = total;
|
|
|
} catch (e) {
|
|
|
@@ -448,14 +625,20 @@ function handleDelete(item: NoticeItem, index: number) {
|
|
|
const cat = noticeCategories.value.find(c => c.key === key);
|
|
|
if (cat && item.unread) cat.unread = Math.max(0, cat.unread - 1);
|
|
|
}
|
|
|
-
|
|
|
-function handleMessageDelete(item: MessageItem, index: number) {
|
|
|
- const key = messageCategory.value;
|
|
|
- messageListByCategory.value[key] = currentMessageList.value.filter((_, i) => i !== index);
|
|
|
- const cat = messageCategories.value.find(c => c.key === key);
|
|
|
- if (cat && item.unread) cat.unread = Math.max(0, cat.unread - 1);
|
|
|
+/** 刷新全部(供 WebSocket 消息到达时实时更新,与商家端一致) */
|
|
|
+function refresh() {
|
|
|
+ if (activeTab.value === "notice") {
|
|
|
+ fetchNoticeUnreadCounts();
|
|
|
+ fetchNoticeList(activeCategory.value);
|
|
|
+ } else {
|
|
|
+ fetchUnfollowedUnreadCount();
|
|
|
+ fetchNoFriendMessage();
|
|
|
+ fetchMessageList();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+defineExpose({ refresh });
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
refreshAllNoticeCategories();
|
|
|
});
|
|
|
@@ -576,12 +759,26 @@ watch(activeTab, val => {
|
|
|
&:last-child {
|
|
|
border-bottom: none;
|
|
|
}
|
|
|
+ &.message-card-clickable {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
.message-avatar {
|
|
|
+ position: relative;
|
|
|
flex-shrink: 0;
|
|
|
+ .message-unread-dot {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ background: var(--el-color-danger);
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
}
|
|
|
.message-body {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
+ cursor: pointer;
|
|
|
}
|
|
|
.message-row {
|
|
|
display: flex;
|
|
|
@@ -605,14 +802,51 @@ watch(activeTab, val => {
|
|
|
}
|
|
|
}
|
|
|
.message-date {
|
|
|
+ flex-shrink: 0;
|
|
|
font-size: 12px;
|
|
|
color: var(--el-text-color-secondary);
|
|
|
}
|
|
|
- .message-content {
|
|
|
+ .message-content-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
margin-bottom: 8px;
|
|
|
+ }
|
|
|
+ .message-content {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ overflow: hidden;
|
|
|
font-size: 14px;
|
|
|
line-height: 1.5;
|
|
|
color: var(--el-text-color-regular);
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ .message-status {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ flex-shrink: 0;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .message-count {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ padding: 0 6px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #ffffff;
|
|
|
+ background: #ff2442;
|
|
|
+ border-radius: 10px;
|
|
|
+ }
|
|
|
+ .message-dot {
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ background: var(--el-color-danger);
|
|
|
+ border-radius: 50%;
|
|
|
}
|
|
|
.message-actions {
|
|
|
display: flex;
|