Merge branch 'yongpxu-dev' of https://e.coding.net/g-xtcy5189/cunkebao/cunkebao_v3 into yongpxu-dev
This commit is contained in:
@@ -0,0 +1,204 @@
|
|||||||
|
.profileSider {
|
||||||
|
background: #fff;
|
||||||
|
border-left: 1px solid #e8e8e8;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.profileContainer {
|
||||||
|
padding: 16px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileHeader {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.closeButton {
|
||||||
|
color: #8c8c8c;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #262626;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileBasic {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
|
||||||
|
.profileInfo {
|
||||||
|
margin-top: 16px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.profileNickname {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #262626;
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileRemark {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.remarkText {
|
||||||
|
color: #8c8c8c;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileStatus {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: #52c41a;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.statusDot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #52c41a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileCard {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
|
||||||
|
|
||||||
|
:global(.ant-card-head) {
|
||||||
|
padding: 0 16px;
|
||||||
|
min-height: 40px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
|
||||||
|
:global(.ant-card-head-title) {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #262626;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.ant-card-body) {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoIcon {
|
||||||
|
color: #8c8c8c;
|
||||||
|
margin-right: 8px;
|
||||||
|
width: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoLabel {
|
||||||
|
color: #8c8c8c;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 60px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoValue {
|
||||||
|
color: #262626;
|
||||||
|
font-size: 14px;
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagsContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
:global(.ant-tag) {
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bioText {
|
||||||
|
margin: 0;
|
||||||
|
color: #595959;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileActions {
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 16px;
|
||||||
|
|
||||||
|
:global(.ant-btn) {
|
||||||
|
border-radius: 6px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式设计
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.profileSider {
|
||||||
|
width: 280px !important;
|
||||||
|
|
||||||
|
.profileContainer {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileBasic {
|
||||||
|
.profileInfo {
|
||||||
|
.profileNickname {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileCard {
|
||||||
|
:global(.ant-card-body) {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoItem {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
.infoLabel {
|
||||||
|
width: 50px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoValue {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
Layout,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
Avatar,
|
||||||
|
Tooltip,
|
||||||
|
Card,
|
||||||
|
Tag,
|
||||||
|
message,
|
||||||
|
} from "antd";
|
||||||
|
import {
|
||||||
|
PhoneOutlined,
|
||||||
|
VideoCameraOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
TeamOutlined,
|
||||||
|
MailOutlined,
|
||||||
|
EnvironmentOutlined,
|
||||||
|
CalendarOutlined,
|
||||||
|
BankOutlined,
|
||||||
|
CloseOutlined,
|
||||||
|
StarOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
CheckOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import { ContractData } from "@/pages/pc/ckbox/data";
|
||||||
|
import { useCkChatStore } from "@/store/module/ckchat";
|
||||||
|
import styles from "./Person.module.scss";
|
||||||
|
|
||||||
|
const { Sider } = Layout;
|
||||||
|
|
||||||
|
interface PersonProps {
|
||||||
|
contract: ContractData;
|
||||||
|
showProfile: boolean;
|
||||||
|
onToggleProfile?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Person: React.FC<PersonProps> = ({
|
||||||
|
contract,
|
||||||
|
showProfile,
|
||||||
|
onToggleProfile,
|
||||||
|
}) => {
|
||||||
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
|
const [isEditingRemark, setIsEditingRemark] = useState(false);
|
||||||
|
const [remarkValue, setRemarkValue] = useState(contract.conRemark || "");
|
||||||
|
|
||||||
|
const kfSelectedUser = useCkChatStore(state => state.kfSelectedUser());
|
||||||
|
|
||||||
|
// 当contract变化时更新备注值
|
||||||
|
useEffect(() => {
|
||||||
|
setRemarkValue(contract.conRemark || "");
|
||||||
|
setIsEditingRemark(false);
|
||||||
|
}, [contract.conRemark]);
|
||||||
|
|
||||||
|
// 处理备注保存
|
||||||
|
const handleSaveRemark = () => {
|
||||||
|
// 这里应该调用API保存备注到后端
|
||||||
|
// 暂时只更新本地状态
|
||||||
|
messageApi.success("备注保存成功");
|
||||||
|
setIsEditingRemark(false);
|
||||||
|
// 更新contract对象中的备注(实际项目中应该通过props回调或状态管理)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理取消编辑
|
||||||
|
const handleCancelEdit = () => {
|
||||||
|
setRemarkValue(contract.conRemark || "");
|
||||||
|
setIsEditingRemark(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟联系人详细信息
|
||||||
|
const contractInfo = {
|
||||||
|
name: contract.name,
|
||||||
|
nickname: contract.nickname,
|
||||||
|
conRemark: remarkValue, // 使用当前编辑的备注值
|
||||||
|
alias: contract.alias,
|
||||||
|
wechatId: contract.wechatId,
|
||||||
|
avatar: contract.avatar,
|
||||||
|
phone: contract.phone || "-",
|
||||||
|
email: contract.email || "-",
|
||||||
|
department: contract.department || "-",
|
||||||
|
position: contract.position || "-",
|
||||||
|
company: contract.company || "-",
|
||||||
|
location: contract.location || "-",
|
||||||
|
joinDate: contract.joinDate || "-",
|
||||||
|
status: "在线",
|
||||||
|
tags: contract.labels,
|
||||||
|
bio: contract.bio || "-",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!showProfile) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{contextHolder}
|
||||||
|
<Sider width={320} className={styles.profileSider}>
|
||||||
|
<div className={styles.profileContainer}>
|
||||||
|
{/* 关闭按钮 */}
|
||||||
|
<div className={styles.profileHeader}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<CloseOutlined />}
|
||||||
|
onClick={onToggleProfile}
|
||||||
|
className={styles.closeButton}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 头像和基本信息 */}
|
||||||
|
<div className={styles.profileBasic}>
|
||||||
|
<Avatar
|
||||||
|
size={80}
|
||||||
|
src={contractInfo.avatar}
|
||||||
|
icon={<UserOutlined />}
|
||||||
|
/>
|
||||||
|
<div className={styles.profileInfo}>
|
||||||
|
<Tooltip
|
||||||
|
title={contractInfo.nickname || contractInfo.name}
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<h4 className={styles.profileNickname}>
|
||||||
|
{contractInfo.nickname || contractInfo.name}
|
||||||
|
</h4>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<div className={styles.profileRemark}>
|
||||||
|
{JSON.stringify(kfSelectedUser)}
|
||||||
|
{isEditingRemark ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "8px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
value={remarkValue}
|
||||||
|
onChange={e => setRemarkValue(e.target.value)}
|
||||||
|
placeholder="请输入备注"
|
||||||
|
size="small"
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<CheckOutlined />}
|
||||||
|
onClick={handleSaveRemark}
|
||||||
|
style={{ color: "#52c41a" }}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<CloseOutlined />}
|
||||||
|
onClick={handleCancelEdit}
|
||||||
|
style={{ color: "#ff4d4f" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "8px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className={styles.remarkText}>
|
||||||
|
{contractInfo.conRemark || "点击添加备注"}
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => setIsEditingRemark(true)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.profileStatus}>
|
||||||
|
<span className={styles.statusDot}></span>
|
||||||
|
{contractInfo.status}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 详细信息卡片 */}
|
||||||
|
<Card title="详细信息" className={styles.profileCard}>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<TeamOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>微信号:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.wechatId}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<UserOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>昵称:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.alias}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<PhoneOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>电话:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.phone}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<MailOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>邮箱:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.email}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<BankOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>部门:</span>
|
||||||
|
<span className={styles.infoValue}>
|
||||||
|
{contractInfo.department}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<StarOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>职位:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.position}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<BankOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>公司:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.company}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<EnvironmentOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>地区:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.location}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<CalendarOutlined className={styles.infoIcon} />
|
||||||
|
<span className={styles.infoLabel}>入职时间:</span>
|
||||||
|
<span className={styles.infoValue}>{contractInfo.joinDate}</span>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* 标签 */}
|
||||||
|
<Card title="标签" className={styles.profileCard}>
|
||||||
|
<div className={styles.tagsContainer}>
|
||||||
|
{contractInfo.tags?.map((tag, index) => (
|
||||||
|
<Tag key={index} color="blue">
|
||||||
|
{tag}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* 个人简介 */}
|
||||||
|
<Card title="个人简介" className={styles.profileCard}>
|
||||||
|
<p className={styles.bioText}>{contractInfo.bio}</p>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* 操作按钮 */}
|
||||||
|
<div className={styles.profileActions}>
|
||||||
|
<Button type="primary" icon={<PhoneOutlined />} block>
|
||||||
|
语音通话
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
icon={<VideoCameraOutlined />}
|
||||||
|
block
|
||||||
|
style={{ marginTop: 8 }}
|
||||||
|
>
|
||||||
|
视频通话
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Sider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Person;
|
||||||
@@ -9,9 +9,6 @@ import {
|
|||||||
Menu,
|
Menu,
|
||||||
message,
|
message,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Badge,
|
|
||||||
Card,
|
|
||||||
Tag,
|
|
||||||
Modal,
|
Modal,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import {
|
import {
|
||||||
@@ -23,14 +20,6 @@ import {
|
|||||||
VideoCameraOutlined,
|
VideoCameraOutlined,
|
||||||
MoreOutlined,
|
MoreOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
TeamOutlined,
|
|
||||||
MailOutlined,
|
|
||||||
EnvironmentOutlined,
|
|
||||||
CalendarOutlined,
|
|
||||||
BankOutlined,
|
|
||||||
CloseOutlined,
|
|
||||||
StarOutlined,
|
|
||||||
EnvironmentOutlined as LocationOutlined,
|
|
||||||
AudioOutlined,
|
AudioOutlined,
|
||||||
AudioOutlined as AudioHoldOutlined,
|
AudioOutlined as AudioHoldOutlined,
|
||||||
DownloadOutlined,
|
DownloadOutlined,
|
||||||
@@ -42,8 +31,9 @@ import {
|
|||||||
FileExcelOutlined,
|
FileExcelOutlined,
|
||||||
FilePptOutlined,
|
FilePptOutlined,
|
||||||
PlayCircleFilled,
|
PlayCircleFilled,
|
||||||
EditOutlined,
|
EnvironmentOutlined,
|
||||||
CheckOutlined,
|
TeamOutlined,
|
||||||
|
StarOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { ChatRecord, ContractData } from "@/pages/pc/ckbox/data";
|
import { ChatRecord, ContractData } from "@/pages/pc/ckbox/data";
|
||||||
import { clearUnreadCount, getMessages } from "@/pages/pc/ckbox/api";
|
import { clearUnreadCount, getMessages } from "@/pages/pc/ckbox/api";
|
||||||
@@ -51,7 +41,8 @@ import styles from "./ChatWindow.module.scss";
|
|||||||
import { useWebSocketStore, WebSocketMessage } from "@/store/module/websocket";
|
import { useWebSocketStore, WebSocketMessage } from "@/store/module/websocket";
|
||||||
import { formatWechatTime } from "@/utils/common";
|
import { formatWechatTime } from "@/utils/common";
|
||||||
import { useCkChatStore } from "@/store/module/ckchat";
|
import { useCkChatStore } from "@/store/module/ckchat";
|
||||||
const { Header, Content, Footer, Sider } = Layout;
|
import Person from "./components/Person";
|
||||||
|
const { Header, Content, Footer } = Layout;
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
interface ChatWindowProps {
|
interface ChatWindowProps {
|
||||||
@@ -75,8 +66,6 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
|
|||||||
const [pendingVideoRequests, setPendingVideoRequests] = useState<
|
const [pendingVideoRequests, setPendingVideoRequests] = useState<
|
||||||
Record<string, string>
|
Record<string, string>
|
||||||
>({});
|
>({});
|
||||||
const [isEditingRemark, setIsEditingRemark] = useState(false);
|
|
||||||
const [remarkValue, setRemarkValue] = useState(contract.conRemark || "");
|
|
||||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const kfSelectedUser = useCkChatStore(state => state.kfSelectedUser());
|
const kfSelectedUser = useCkChatStore(state => state.kfSelectedUser());
|
||||||
@@ -100,12 +89,6 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
|
|||||||
});
|
});
|
||||||
}, [contract.id]);
|
}, [contract.id]);
|
||||||
|
|
||||||
// 当contract变化时更新备注值
|
|
||||||
useEffect(() => {
|
|
||||||
setRemarkValue(contract.conRemark || "");
|
|
||||||
setIsEditingRemark(false);
|
|
||||||
}, [contract.conRemark]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 只有在非视频加载操作时才自动滚动到底部
|
// 只有在非视频加载操作时才自动滚动到底部
|
||||||
// 检查是否有视频正在加载中
|
// 检查是否有视频正在加载中
|
||||||
@@ -792,21 +775,6 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理备注保存
|
|
||||||
const handleSaveRemark = () => {
|
|
||||||
// 这里应该调用API保存备注到后端
|
|
||||||
// 暂时只更新本地状态
|
|
||||||
messageApi.success("备注保存成功");
|
|
||||||
setIsEditingRemark(false);
|
|
||||||
// 更新contract对象中的备注(实际项目中应该通过props回调或状态管理)
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理取消编辑
|
|
||||||
const handleCancelEdit = () => {
|
|
||||||
setRemarkValue(contract.conRemark || "");
|
|
||||||
setIsEditingRemark(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const chatMenu = (
|
const chatMenu = (
|
||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item key="profile" icon={<UserOutlined />}>
|
<Menu.Item key="profile" icon={<UserOutlined />}>
|
||||||
@@ -828,26 +796,6 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
|
|||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
// 模拟联系人详细信息
|
|
||||||
const contractInfo = {
|
|
||||||
name: contract.name,
|
|
||||||
nickname: contract.nickname,
|
|
||||||
conRemark: remarkValue, // 使用当前编辑的备注值
|
|
||||||
alias: contract.alias,
|
|
||||||
wechatId: contract.wechatId,
|
|
||||||
avatar: contract.avatar,
|
|
||||||
phone: contract.phone || "-",
|
|
||||||
email: contract.email || "-",
|
|
||||||
department: contract.department || "-",
|
|
||||||
position: contract.position || "-",
|
|
||||||
company: contract.company || "-",
|
|
||||||
location: contract.location || "-",
|
|
||||||
joinDate: contract.joinDate || "-",
|
|
||||||
status: "在线",
|
|
||||||
tags: contract.labels,
|
|
||||||
bio: contract.bio || "-",
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout className={styles.chatWindow}>
|
<Layout className={styles.chatWindow}>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
@@ -944,7 +892,7 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
|
|||||||
<Tooltip title="位置">
|
<Tooltip title="位置">
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<LocationOutlined />}
|
icon={<EnvironmentOutlined />}
|
||||||
className={styles.toolbarButton}
|
className={styles.toolbarButton}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1033,165 +981,11 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
|
|||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
{/* 右侧个人资料卡片 */}
|
{/* 右侧个人资料卡片 */}
|
||||||
{showProfile && (
|
<Person
|
||||||
<Sider width={330} className={styles.profileSider}>
|
contract={contract}
|
||||||
<div className={styles.profileSiderContent}>
|
showProfile={showProfile}
|
||||||
<div className={styles.profileHeader}>
|
onToggleProfile={onToggleProfile}
|
||||||
<h3>个人资料</h3>
|
/>
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<CloseOutlined />}
|
|
||||||
onClick={onToggleProfile}
|
|
||||||
className={styles.closeButton}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.profileContent}>
|
|
||||||
{/* 基本信息 */}
|
|
||||||
<Card className={styles.profileCard}>
|
|
||||||
<div className={styles.profileBasic}>
|
|
||||||
<Avatar
|
|
||||||
size={80}
|
|
||||||
src={contractInfo.avatar}
|
|
||||||
icon={<UserOutlined />}
|
|
||||||
/>
|
|
||||||
<div className={styles.profileInfo}>
|
|
||||||
<Tooltip
|
|
||||||
title={contractInfo.nickname || contractInfo.name}
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<h4 className={styles.profileNickname}>
|
|
||||||
{contractInfo.nickname || contractInfo.name}
|
|
||||||
</h4>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
<div className={styles.profileRemark}>
|
|
||||||
{JSON.stringify(kfSelectedUser)}
|
|
||||||
{isEditingRemark ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "8px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
value={remarkValue}
|
|
||||||
onChange={e => setRemarkValue(e.target.value)}
|
|
||||||
placeholder="请输入备注"
|
|
||||||
size="small"
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
icon={<CheckOutlined />}
|
|
||||||
onClick={handleSaveRemark}
|
|
||||||
style={{ color: "#52c41a" }}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
icon={<CloseOutlined />}
|
|
||||||
onClick={handleCancelEdit}
|
|
||||||
style={{ color: "#ff4d4f" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "8px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>备注: {contractInfo.conRemark || "无"}</span>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
icon={<EditOutlined />}
|
|
||||||
onClick={() => setIsEditingRemark(true)}
|
|
||||||
style={{ color: "#1890ff" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className={styles.profileWechatId}>
|
|
||||||
微信号: {contractInfo.alias || contractInfo.wechatId}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* 联系信息 */}
|
|
||||||
<Card title="联系信息" className={styles.profileCard}>
|
|
||||||
<div className={styles.contractInfo}>
|
|
||||||
<div className={styles.contractItem}>
|
|
||||||
<PhoneOutlined />
|
|
||||||
<span className={styles.contractItemText}>
|
|
||||||
{contractInfo.phone}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.contractItem}>
|
|
||||||
<MailOutlined />
|
|
||||||
<span className={styles.contractItemText}>
|
|
||||||
{contractInfo.email}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.contractItem}>
|
|
||||||
<EnvironmentOutlined />
|
|
||||||
<span className={styles.contractItemText}>
|
|
||||||
{contractInfo.location}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.contractItem}>
|
|
||||||
<BankOutlined />
|
|
||||||
<span className={styles.contractItemText}>
|
|
||||||
{contractInfo.company}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.contractItem}>
|
|
||||||
<CalendarOutlined />
|
|
||||||
<span className={styles.contractItemText}>
|
|
||||||
入职时间:{contractInfo.joinDate}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* 标签 */}
|
|
||||||
<Card title="标签" className={styles.profileCard}>
|
|
||||||
<div className={styles.tagsContainer}>
|
|
||||||
{contractInfo.tags.map((tag, index) => (
|
|
||||||
<Tag key={index} color="blue">
|
|
||||||
{tag}
|
|
||||||
</Tag>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* 个人简介 */}
|
|
||||||
<Card title="个人简介" className={styles.profileCard}>
|
|
||||||
<p className={styles.bioText}>{contractInfo.bio}</p>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* 操作按钮 */}
|
|
||||||
<div className={styles.profileActions}>
|
|
||||||
<Button type="primary" icon={<PhoneOutlined />} block>
|
|
||||||
语音通话
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
icon={<VideoCameraOutlined />}
|
|
||||||
block
|
|
||||||
style={{ marginTop: 8 }}
|
|
||||||
>
|
|
||||||
视频通话
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Sider>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 素材选择模态框 */}
|
{/* 素材选择模态框 */}
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
Reference in New Issue
Block a user