新增右键菜单功能,支持会话置顶、删除和修改备注操作;更新样式以提升用户交互体验,优化会话信息展示逻辑。
This commit is contained in:
@@ -120,6 +120,43 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 右键菜单样式
|
||||
.contextMenu {
|
||||
background: white;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
box-shadow:
|
||||
0 6px 16px 0 rgba(0, 0, 0, 0.08),
|
||||
0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
||||
0 9px 28px 8px rgba(0, 0, 0, 0.05);
|
||||
padding: 4px 0;
|
||||
min-width: 120px;
|
||||
z-index: 1000;
|
||||
|
||||
.menuItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #262626;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.messageList {
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface ContractData {
|
||||
lastMessageTime: number;
|
||||
config: {
|
||||
unreadCount: number;
|
||||
top?: boolean;
|
||||
};
|
||||
duplicate: boolean;
|
||||
[key: string]: any;
|
||||
@@ -43,6 +44,7 @@ export interface ChatSession {
|
||||
lastTime: string;
|
||||
config: {
|
||||
unreadCount: number;
|
||||
top?: boolean;
|
||||
};
|
||||
online: boolean;
|
||||
members?: string[];
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { List, Avatar, Badge } from "antd";
|
||||
import { UserOutlined, TeamOutlined } from "@ant-design/icons";
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { List, Avatar, Badge, Modal, Input, message } from "antd";
|
||||
import {
|
||||
UserOutlined,
|
||||
TeamOutlined,
|
||||
PushpinOutlined,
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
|
||||
import { useWeChatStore } from "@/store/module/weChat/weChat";
|
||||
import { useCkChatStore } from "@/store/module/ckchat/ckchat";
|
||||
|
||||
import { updateConfig } from "@/pages/pc/ckbox/api";
|
||||
import styles from "./MessageList.module.scss";
|
||||
import { formatWechatTime } from "@/utils/common";
|
||||
interface MessageListProps {}
|
||||
@@ -22,6 +28,138 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
(ContractData | weChatGroup)[]
|
||||
>([]);
|
||||
const searchKeyword = useCkChatStore(state => state.searchKeyword);
|
||||
|
||||
// 右键菜单相关状态
|
||||
const [contextMenu, setContextMenu] = useState<{
|
||||
visible: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
session: ContractData | weChatGroup | null;
|
||||
}>({
|
||||
visible: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
session: null,
|
||||
});
|
||||
|
||||
// 修改备注相关状态
|
||||
const [editRemarkModal, setEditRemarkModal] = useState<{
|
||||
visible: boolean;
|
||||
session: ContractData | weChatGroup | null;
|
||||
remark: string;
|
||||
}>({
|
||||
visible: false,
|
||||
session: null,
|
||||
remark: "",
|
||||
});
|
||||
|
||||
const contextMenuRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 右键菜单事件处理
|
||||
const handleContextMenu = (
|
||||
e: React.MouseEvent,
|
||||
session: ContractData | weChatGroup,
|
||||
) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
setContextMenu({
|
||||
visible: true,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
session,
|
||||
});
|
||||
};
|
||||
|
||||
// 隐藏右键菜单
|
||||
const hideContextMenu = () => {
|
||||
setContextMenu({
|
||||
visible: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
session: null,
|
||||
});
|
||||
};
|
||||
|
||||
// 置顶/取消置顶
|
||||
const handleTogglePin = (session: ContractData | weChatGroup) => {
|
||||
const isPinned = (session.config as any)?.top || true;
|
||||
updateConfig({
|
||||
id: session.id,
|
||||
config: { top: isPinned, chat: true },
|
||||
})
|
||||
.then(() => {
|
||||
message.success(`${isPinned ? "取消置顶" : "置顶"}成功`);
|
||||
//更新当前这个item的config的top值
|
||||
//并把当前的Item移动到聊天列表的最上方
|
||||
})
|
||||
.catch(() => {
|
||||
message.error(`${isPinned ? "取消置顶" : "置顶"}失败`);
|
||||
//更新当前这个item的config的top值
|
||||
//先计算一下最后一个置顶的坐标,并把当前的Item移动到最后一个置顶的 Item下边
|
||||
});
|
||||
hideContextMenu();
|
||||
};
|
||||
|
||||
// 删除会话
|
||||
const handleDelete = (session: ContractData | weChatGroup) => {
|
||||
Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: `确定要删除与 ${session.conRemark || session.nickname} 的会话吗?`,
|
||||
onOk: () => {
|
||||
// TODO: 调用API删除会话
|
||||
console.log("删除会话", session);
|
||||
message.success("删除成功");
|
||||
hideContextMenu();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 修改备注
|
||||
const handleEditRemark = (session: ContractData | weChatGroup) => {
|
||||
setEditRemarkModal({
|
||||
visible: true,
|
||||
session,
|
||||
remark: session.conRemark || "",
|
||||
});
|
||||
hideContextMenu();
|
||||
};
|
||||
|
||||
// 保存备注
|
||||
const handleSaveRemark = () => {
|
||||
if (!editRemarkModal.session) return;
|
||||
|
||||
// TODO: 调用API更新备注
|
||||
console.log("更新备注", editRemarkModal.session, editRemarkModal.remark);
|
||||
message.success("备注更新成功");
|
||||
|
||||
setEditRemarkModal({
|
||||
visible: false,
|
||||
session: null,
|
||||
remark: "",
|
||||
});
|
||||
};
|
||||
|
||||
// 点击外部隐藏菜单
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
contextMenuRef.current &&
|
||||
!contextMenuRef.current.contains(event.target as Node)
|
||||
) {
|
||||
hideContextMenu();
|
||||
}
|
||||
};
|
||||
|
||||
if (contextMenu.visible) {
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, [contextMenu.visible]);
|
||||
|
||||
useEffect(() => {
|
||||
let filteredSessions = getChatSessions;
|
||||
|
||||
@@ -55,6 +193,7 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
currentContract?.id === session.id ? styles.active : ""
|
||||
}`}
|
||||
onClick={() => onContactClick(session)}
|
||||
onContextMenu={e => handleContextMenu(e, session)}
|
||||
>
|
||||
<div className={styles.messageInfo}>
|
||||
<Badge count={session.config.unreadCount || 0} size="small">
|
||||
@@ -73,7 +212,7 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
<div className={styles.messageDetails}>
|
||||
<div className={styles.messageHeader}>
|
||||
<div className={styles.messageName}>
|
||||
{session.conRemark || session.nickname}
|
||||
{session.conRemark || session.nickname || session.wechatId}
|
||||
</div>
|
||||
<div className={styles.messageTime}>
|
||||
{formatWechatTime(session?.lastUpdateTime)}
|
||||
@@ -84,6 +223,70 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 右键菜单 */}
|
||||
{contextMenu.visible && contextMenu.session && (
|
||||
<div
|
||||
ref={contextMenuRef}
|
||||
className={styles.contextMenu}
|
||||
style={{
|
||||
position: "fixed",
|
||||
left: contextMenu.x,
|
||||
top: contextMenu.y,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={styles.menuItem}
|
||||
onClick={() => handleTogglePin(contextMenu.session!)}
|
||||
>
|
||||
<PushpinOutlined />
|
||||
{(contextMenu.session.config as any)?.top ? "取消置顶" : "置顶"}
|
||||
</div>
|
||||
<div
|
||||
className={styles.menuItem}
|
||||
onClick={() => handleEditRemark(contextMenu.session!)}
|
||||
>
|
||||
<EditOutlined />
|
||||
修改备注
|
||||
</div>
|
||||
<div
|
||||
className={styles.menuItem}
|
||||
onClick={() => handleDelete(contextMenu.session!)}
|
||||
>
|
||||
<DeleteOutlined />
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 修改备注Modal */}
|
||||
<Modal
|
||||
title="修改备注"
|
||||
open={editRemarkModal.visible}
|
||||
onOk={handleSaveRemark}
|
||||
onCancel={() =>
|
||||
setEditRemarkModal({
|
||||
visible: false,
|
||||
session: null,
|
||||
remark: "",
|
||||
})
|
||||
}
|
||||
okText="保存"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Input
|
||||
value={editRemarkModal.remark}
|
||||
onChange={e =>
|
||||
setEditRemarkModal(prev => ({
|
||||
...prev,
|
||||
remark: e.target.value,
|
||||
}))
|
||||
}
|
||||
placeholder="请输入备注"
|
||||
maxLength={20}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user