blob: 374ac836a4b760b90c8d6c2a2bd8bd8abd0be3df [file] [log] [blame]
import React, { useState, useEffect } from 'react';
import {
Input,
Button,
List,
Typography,
Space,
Spin,
Popconfirm,
message,
Divider,
Avatar,
} from 'antd';
import {
UserAddOutlined,
DeleteOutlined,
ReloadOutlined,
CheckOutlined,
CloseOutlined,
} from '@ant-design/icons';
import {
addFriend,
deleteFriend,
getFriendsByUserId,
getPendingRequests,
acceptFriend,
rejectFriend,
} from '../api/friends';
import axios from 'axios';
const { Title, Text } = Typography;
const FriendManager = ({ currentUser, onSelectRelation }) => {
const currentUserId = currentUser?.userid;
const [friendName, setFriendName] = useState('');
const [friends, setFriends] = useState([]);
const [pendingRequests, setPendingRequests] = useState([]);
const [userInfoMap, setUserInfoMap] = useState({});
const [loading, setLoading] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [pendingLoading, setPendingLoading] = useState(false);
useEffect(() => {
if (currentUserId) {
refreshData();
}
}, [currentUserId]);
const refreshData = () => {
loadFriends(currentUserId);
loadPendingRequests(currentUserId);
};
const fetchUserInfo = async (userId) => {
if (userInfoMap[userId]) return;
try {
const res = await axios.get(`http://localhost:8080/user/getDecoration?userid=${userId}`);
const info = res.data?.data;
if (info) {
setUserInfoMap((prev) => ({
...prev,
[userId]: {
username: info.username,
avatar: info.image,
},
}));
}
} catch {
setUserInfoMap((prev) => ({
...prev,
[userId]: {
username: `用户${userId}`,
avatar: null,
},
}));
}
};
const loadFriends = async (userId) => {
setRefreshing(true);
try {
const res = await getFriendsByUserId(userId);
const list = res.data || [];
setFriends(list);
list.forEach(f => fetchUserInfo(getFriendUserId(f)));
} catch {
message.error('加载好友失败,请稍后重试');
}
setRefreshing(false);
};
const loadPendingRequests = async (userId) => {
setPendingLoading(true);
try {
const res = await getPendingRequests(userId);
const list = res.data || [];
setPendingRequests(list);
list.forEach(req => {
const otherId = req.friend1 === currentUserId ? req.friend2 : req.friend1;
fetchUserInfo(otherId);
});
} catch {
message.error('加载好友申请失败');
}
setPendingLoading(false);
};
const handleAddFriend = async () => {
if (!friendName.trim()) return message.warning('请输入好友用户名');
setLoading(true);
try {
const res = await axios.get(`http://localhost:8080/user/getUserid?username=${friendName.trim()}`);
const newFriendId = res.data?.data;
if (!newFriendId) {
message.error('未找到该用户名对应的用户');
setLoading(false);
return;
}
if (newFriendId === currentUserId) {
message.warning('不能添加自己为好友');
setLoading(false);
return;
}
const isAlreadyFriend = friends.some(f =>
(f.friend1 === currentUserId && f.friend2 === newFriendId) ||
(f.friend1 === newFriendId && f.friend2 === currentUserId)
);
if (isAlreadyFriend) {
message.warning('该用户已是您的好友');
setLoading(false);
return;
}
const result = await addFriend({ friend1: currentUserId, friend2: newFriendId });
if (result.data) {
message.success('好友请求已发送');
setFriendName('');
loadPendingRequests(currentUserId);
} else {
message.error('添加失败');
}
} catch {
message.error('添加好友失败,请稍后重试');
} finally {
setLoading(false);
}
};
const handleDelete = async (friend1, friend2) => {
setLoading(true);
try {
const res = await deleteFriend(friend1, friend2);
if (res.data) {
message.success('删除成功');
loadFriends(currentUserId);
} else {
message.error('删除失败');
}
} catch {
message.error('删除好友失败');
} finally {
setLoading(false);
}
};
const handleAccept = async (friend1, friend2) => {
setPendingLoading(true);
try {
const res = await acceptFriend(friend1, friend2);
if (res.data) {
message.success('已同意好友请求');
refreshData();
} else {
message.error('操作失败');
}
} catch {
message.error('同意失败');
} finally {
setPendingLoading(false);
}
};
const handleReject = async (friend1, friend2) => {
setPendingLoading(true);
try {
const res = await rejectFriend(friend1, friend2);
if (res.data) {
message.info('已拒绝好友请求');
loadPendingRequests(currentUserId);
} else {
message.error('操作失败');
}
} catch {
message.error('拒绝失败');
} finally {
setPendingLoading(false);
}
};
const getFriendUserId = (f) => f.friend1 === currentUserId ? f.friend2 : f.friend1;
const renderUserMeta = (userId, timeLabel) => {
const user = userInfoMap[userId] || {};
return {
avatar: <Avatar src={user.avatar} />,
title: user.username ? `${user.username}(ID: ${userId})` : `用户ID:${userId}`,
description: timeLabel,
};
};
return (
<div style={{ maxWidth: 700, margin: 'auto', padding: 24 }}>
<Title level={3} style={{ textAlign: 'center', marginBottom: 24 }}>
好友管理
</Title>
<Space style={{ marginBottom: 24 }} align="start">
<Input
placeholder="输入好友用户名"
value={friendName}
onChange={(e) => setFriendName(e.target.value)}
style={{ width: 220 }}
allowClear
prefix={<UserAddOutlined />}
/>
<Button
type="primary"
loading={loading}
onClick={handleAddFriend}
disabled={!friendName.trim()}
>
添加好友
</Button>
</Space>
<Divider />
<Title level={4}>好友申请</Title>
<Spin spinning={pendingLoading}>
{pendingRequests.length === 0 ? (
<Text type="secondary">暂无好友申请</Text>
) : (
<List
itemLayout="horizontal"
dataSource={pendingRequests}
renderItem={(item) => {
const otherId = item.friend1 === currentUserId ? item.friend2 : item.friend1;
return (
<List.Item
actions={[
<Button
key="accept"
type="primary"
icon={<CheckOutlined />}
onClick={() => handleAccept(item.friend1, item.friend2)}
loading={pendingLoading}
size="small"
>
同意
</Button>,
<Popconfirm
key="reject"
title="确定拒绝该好友请求?"
onConfirm={() => handleReject(item.friend1, item.friend2)}
okText="确认"
cancelText="取消"
>
<Button
danger
icon={<CloseOutlined />}
loading={pendingLoading}
size="small"
>
拒绝
</Button>
</Popconfirm>,
]}
>
<List.Item.Meta {...renderUserMeta(otherId, `申请时间:${new Date(item.requestTime).toLocaleString()}`)} />
</List.Item>
);
}}
/>
)}
</Spin>
<Divider />
<Space align="center" style={{ marginBottom: 12, justifyContent: 'space-between', width: '100%' }}>
<Title level={4} style={{ margin: 0 }}>
我的好友列表
</Title>
<Button
icon={<ReloadOutlined />}
onClick={() => refreshData()}
loading={refreshing || pendingLoading}
type="link"
>
刷新
</Button>
</Space>
<Spin spinning={refreshing}>
{friends.length === 0 ? (
<Text type="secondary">暂无好友</Text>
) : (
<List
itemLayout="horizontal"
dataSource={friends}
renderItem={(f) => {
const friendUserId = getFriendUserId(f);
return (
<List.Item
onClick={() =>
onSelectRelation({
relationid: f.relationid,
friendId: friendUserId,
})
}
style={{ cursor: 'pointer' }}
actions={[
<Popconfirm
title="确定删除该好友?"
onConfirm={(e) => {
e.stopPropagation();
handleDelete(f.friend1, f.friend2);
}}
okText="确认"
cancelText="取消"
key="delete"
>
<Button
danger
icon={<DeleteOutlined />}
loading={loading}
size="small"
>
删除
</Button>
</Popconfirm>,
]}
>
<List.Item.Meta
{...renderUserMeta(friendUserId, `添加时间:${new Date(f.requestTime).toLocaleString()}`)}
/>
</List.Item>
);
}}
/>
)}
</Spin>
</div>
);
};
export default FriendManager;