blob: 3e634825b7645ace4e62bc07f1be7a2e8ecfa32d [file] [log] [blame]
import React, { useState, useEffect } from 'react';
import {
createRequest,
deleteRequest,
updateMoney,
findByUserid,
findByName,
getTotalMoneyByName,
updateLoaduserByName,
getAllRequests
} from '../api/request';
import { useSetState } from '@mantine/hooks';
import { useNavigate } from 'react-router-dom';
import './RequestBoard.css';
const RequestBoard = ({ currentUserId, onBack }) => {
const storedUser = localStorage.getItem('user');
//let currentUserId = null; // 初始化为 null
if (storedUser) {
try {
const parsedUser = JSON.parse(storedUser);
currentUserId = parsedUser.userid; // 直接赋值
} catch (error) {
console.error('解析用户数据失败:', error);
// 可以在这里处理 JSON 解析错误(如数据损坏)
}
} else {
console.log('用户未登录');
}
// 现在 currentUserId 可以在后续逻辑中使用
console.log('当前用户ID:', currentUserId);
const [requests, setRequests] = useState([]);
const [allRequests, setAllRequests] = useState([]);
const [searchedRequests, setSearchedRequests] = useState([]);
const [userInfos, setUserInfos] = useState({}); // 存储所有用户信息:{ userid: { username, avatar } }
const navigate = useNavigate();
const [formData, setFormData] = useState({
userid: currentUserId,
name: '',
plot: '',
money: '',
year: '',
country: '',
photo: null,
});
const [searchName, setSearchName] = useState('');
const [totalMoney, setTotalMoney] = useState(null);
const [viewMode, setViewMode] = useState('my');
const [showForm, setShowForm] = useState(false); // 控制表单折叠
// 获取用户信息的函数
const fetchUserInfo = async (userId) => {
try {
// 如果已经获取过该用户的信息,直接返回
if (userInfos[userId]) return;
const response = await fetch(`http://localhost:8080/user/getDecoration?userid=${userId}`);
if (response.ok) {
const data = await response.json();
if (data.success) {
// 更新用户信息状态
setUserInfos(prev => ({
...prev,
[userId]: {
username: data.data.username,
avatar: data.data.image,
decoration: data.data.decoration
}
}));
} else {
console.error('获取用户信息失败:', data.message);
}
} else {
console.error('获取用户信息失败:', response.statusText);
}
} catch (error) {
console.error('获取用户信息出错:', error);
}
};
useEffect(() => {
loadUserRequests();
loadAllRequests();
}, [currentUserId]);
const loadUserRequests = async () => {
const data = await findByUserid(currentUserId);
setRequests(data);
// 为每个需求贴获取用户信息
data.forEach(request => {
fetchUserInfo(request.userid); // 获取创建者信息
if (request.loaduser) {
fetchUserInfo(request.loaduser); // 获取接管者信息
}
});
};
const loadAllRequests = async () => {
const data = await getAllRequests();
setAllRequests(data);
// 为每个需求贴获取用户信息
data.forEach(request => {
fetchUserInfo(request.userid); // 获取创建者信息
if (request.loaduser) {
fetchUserInfo(request.loaduser); // 获取接管者信息
}
});
};
// 处理搜索的需求贴
const processSearchedRequests = (data) => {
setSearchedRequests(data);
// 为每个需求贴获取用户信息
data.forEach(request => {
fetchUserInfo(request.userid); // 获取创建者信息
if (request.loaduser) {
fetchUserInfo(request.loaduser); // 获取接管者信息
}
});
};
const handleChange = (e) => {
const { name, value, files } = e.target;
setFormData((prev) => ({
...prev,
[name]: files ? files[0] : value,
}));
};
const handleCreate = async (e) => {
e.preventDefault();
const fd = new FormData();
Object.entries(formData).forEach(([key, value]) => {
if (value !== '' && value !== null) fd.append(key, value);
});
const res = await createRequest(fd);
if (res.data === true) {
alert('创建成功');
setFormData(prev => ({
...prev,
name: '',
plot: '',
money: '',
year: '',
country: '',
photo: null,
}));
setShowForm(false);
loadUserRequests();
loadAllRequests();
} else {
alert('创建失败');
}
};
const handleDelete = async (id) => {
if (window.confirm('确定要删除这个需求贴吗?')) {
await deleteRequest(id);
loadUserRequests();
loadAllRequests();
}
};
const handleUpdateMoney = async (id, newMoney) => {
if (!newMoney) return;
await updateMoney(id, newMoney);
loadUserRequests();
};
const handleSearch = async () => {
if (!searchName.trim()) {
alert('请输入搜索关键词');
return;
}
const data = await findByName(searchName);
const total = await getTotalMoneyByName(searchName);
setTotalMoney(total);
setViewMode('search');
processSearchedRequests(data);
};
const handleProcess = (request) => {
navigate(`/uploadfull/${request.requestid}`, {
state: {
requestid: request.requestid
},
});
};
const handleUploadLoaduser = async (name, requestid) => {
if (window.confirm(`确定要接管 "${name}" 的所有需求贴吗?`)) {
try {
await updateLoaduserByName(name, currentUserId);
alert('接管成功');
handleProcess({ requestid: requestid });
console.log(requestid);
loadUserRequests();
loadAllRequests();
} catch (error) {
alert('接管失败,请稍后重试');
console.error(error);
}
}
};
// 渲染用户信息展示
const renderUserInfo = (userId, prefix = '') => {
if (!userId) return null;
const userInfo = userInfos[userId];
return (
<div className="request-user-info">
<div className="flex items-center gap-2">
<div className="request-user-avatar">
{userInfo?.avatar ? (
<img
src={userInfo.avatar}
alt={`${prefix}头像`}
className="w-8 h-8 rounded-full object-cover border-2 border-orange-200 sm:w-6 sm:h-6"
/>
) : (
<div className="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center text-gray-500 text-xs border-2 border-orange-200 sm:w-6 sm:h-6">
{prefix.charAt(0)}
</div>
)}
</div>
<div className="request-user-details">
<div className="text-xs sm:text-[11px] font-medium text-gray-600">
{prefix}:
</div>
<div className="text-sm sm:text-xs font-medium text-orange-600 truncate max-w-[100px]">
{userInfo?.username || `用户${userId}`}
</div>
</div>
</div>
</div>
);
};
const renderActions = (request) => {
if (request.userid === currentUserId) {
return (
<div className="flex flex-col sm:flex-row gap-2 w-full">
<div className="flex gap-2 flex-1">
<input
type="number"
placeholder="新金额"
onChange={(e) => handleUpdateMoney(request.requestid, e.target.value)}
className="request-input flex-1 text-center py-1 sm:py-0"
/>
<button
onClick={() => handleDelete(request.requestid)}
className="request-button request-button-delete"
>
删除
</button>
</div>
</div>
);
}
return (
<button
onClick={() => handleUploadLoaduser(request.name, request.requestid)}
className="request-button request-button-takeover"
>
接管任务
</button>
);
};
return (
<div className="request-container">
<div className="request-header">
<div className="flex flex-col lg:flex-row justify-between gap-4 mb-6">
<h1 className="text-2xl font-bold text-orange-700 sm:text-xl">需求贴发布区</h1>
<div className="flex flex-wrap gap-2">
<button
className={`request-tab ${viewMode === 'my' ? 'request-tab-active' : ''}`}
onClick={() => setViewMode('my')}
>
我的需求贴
</button>
<button
className={`request-tab ${viewMode === 'all' ? 'request-tab-active' : ''}`}
onClick={() => setViewMode('all')}
>
所有需求贴
</button>
<button
className="request-button request-button-back"
onClick={onBack}
>
返回主页面
</button>
<button
onClick={() => setShowForm(!showForm)}
className="request-button request-button-create"
>
{showForm ? '收起表单' : '创建新需求贴'}
</button>
</div>
</div>
{/* 折叠表单 */}
{showForm && (
<form className="request-form" onSubmit={handleCreate}>
<h2 className="text-xl font-semibold text-orange-700 mb-4 sm:text-lg">发布新需求</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="request-label">需求标题 *</label>
<input
name="name"
placeholder="请输入需求标题"
className="request-input"
value={formData.name}
onChange={handleChange}
required
/>
</div>
<div>
<label className="request-label">所需金额 (¥) *</label>
<input
name="money"
type="number"
placeholder="请输入金额"
className="request-input"
value={formData.money}
onChange={handleChange}
min="1"
required
/>
</div>
</div>
<div className="mt-4">
<label className="request-label">详细描述 *</label>
<textarea
name="plot"
placeholder="请详细描述您的需求..."
className="request-textarea"
value={formData.plot}
onChange={handleChange}
required
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
<div>
<label className="request-label">年份</label>
<input
name="year"
type="number"
placeholder="如:2023"
className="request-input"
value={formData.year}
onChange={handleChange}
/>
</div>
<div>
<label className="request-label">国家/地区</label>
<input
name="country"
placeholder="如:中国"
className="request-input"
value={formData.country}
onChange={handleChange}
/>
</div>
<div>
<label className="request-label">相关图片</label>
<input
name="photo"
type="file"
className="request-file"
onChange={handleChange}
/>
</div>
</div>
<button
type="submit"
className="request-button request-button-submit mt-6"
>
发布需求贴
</button>
</form>
)}
</div>
{/* 搜索区域 */}
<div className="request-search">
<h2 className="text-xl font-semibold text-orange-700 mb-4 sm:text-lg">搜索需求贴</h2>
<div className="flex flex-col sm:flex-row gap-3">
<input
type="text"
placeholder="输入需求标题关键词..."
value={searchName}
onChange={(e) => setSearchName(e.target.value)}
className="request-input flex-1"
/>
<button
onClick={handleSearch}
className="request-button request-button-search"
>
搜索需求
</button>
</div>
{totalMoney !== null && viewMode === 'search' && (
<div className="request-money-total mt-4">
<span className="font-medium">"{searchName}" 需求总金额:</span>
<span className="font-bold text-red-600 ml-2">¥{totalMoney}</span>
</div>
)}
</div>
{/* 搜索结果 */}
{viewMode === 'search' && searchedRequests.length > 0 && (
<div className="request-results">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-6 gap-3">
<h2 className="text-xl font-semibold text-orange-700 sm:text-lg">
搜索结果:<span className="text-orange-500">{searchedRequests.length}</span> 条需求
</h2>
<button
onClick={() => setViewMode('my')}
className="request-button request-button-back"
>
返回我的需求
</button>
</div>
<div className="request-cards">
{searchedRequests.map((request) => (
<div key={request.requestid} className="request-card">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
<div className="flex-1 min-w-0">
<h3 className="request-card-title">{request.name}</h3>
<div className="request-card-money">¥{request.money}</div>
</div>
<div className="request-user-info-container">
{renderUserInfo(request.userid, '创建者')}
{request.loaduser && (
<>
<div className="request-user-divider"></div>
{renderUserInfo(request.loaduser, '接管者')}
</>
)}
</div>
</div>
<div className="request-card-content">
{request.plot}
</div>
<div className="request-card-meta">
{request.year && (
<div className="request-meta-item">
<span className="request-meta-label">年份:</span>
<span>{request.year}</span>
</div>
)}
{request.country && (
<div className="request-meta-item">
<span className="request-meta-label">地区:</span>
<span>{request.country}</span>
</div>
)}
<div className="request-meta-item">
<span className="request-meta-label">发布时间:</span>
<span>{new Date(request.requestTime).toLocaleString()}</span>
</div>
</div>
{request.photo && (
<div className="request-card-image-container">
<img
src={`http://localhost:8080${request.photo}`}
alt="需求贴配图"
className="request-card-image"
/>
</div>
)}
<div className="request-card-actions">
{renderActions(request)}
</div>
</div>
))}
</div>
</div>
)}
{/* 我的需求贴 */}
{viewMode === 'my' && (
<div className="request-my">
<h2 className="text-xl font-semibold text-orange-700 mb-6 sm:text-lg">我的需求贴</h2>
{requests.length === 0 ? (
<div className="request-empty">
<div className="request-empty-icon">📋</div>
<p className="request-empty-text">您还没有发布任何需求贴</p>
<button
className="request-button request-button-create mt-4"
onClick={() => {
setShowForm(true);
document.querySelector('.request-form')?.scrollIntoView({ behavior: 'smooth' });
}}
>
立即发布需求
</button>
</div>
) : (
<div className="request-cards">
{requests.map((request) => (
<div key={request.requestid} className="request-card">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
<div className="flex-1 min-w-0">
<h3 className="request-card-title">{request.name}</h3>
<div className="request-card-money">¥{request.money}</div>
</div>
<div className="request-user-info-container">
{renderUserInfo(request.userid, '创建者')}
{request.loaduser && (
<>
<div className="request-user-divider"></div>
{renderUserInfo(request.loaduser, '接管者')}
</>
)}
</div>
</div>
<div className="request-card-content">
{request.plot}
</div>
<div className="request-card-meta">
{request.year && (
<div className="request-meta-item">
<span className="request-meta-label">年份:</span>
<span>{request.year}</span>
</div>
)}
{request.country && (
<div className="request-meta-item">
<span className="request-meta-label">地区:</span>
<span>{request.country}</span>
</div>
)}
<div className="request-meta-item">
<span className="request-meta-label">发布时间:</span>
<span>{new Date(request.requestTime).toLocaleString()}</span>
</div>
</div>
{request.photo && (
<div className="request-card-image-container">
<img
src={`http://localhost:8080${request.photo}`}
alt="需求贴配图"
className="request-card-image"
/>
</div>
)}
<div className="request-card-actions">
{renderActions(request)}
</div>
</div>
))}
</div>
)}
</div>
)}
{/* 所有需求贴 */}
{viewMode === 'all' && (
<div className="request-all">
<div className="flex justify-between items-center mb-6">
<h2 className="text-xl font-semibold text-orange-700 sm:text-lg">所有需求贴</h2>
<span className="text-gray-600">共 {allRequests.length} 条需求</span>
</div>
{allRequests.length === 0 ? (
<div className="request-empty">
<div className="request-empty-icon">📭</div>
<p className="request-empty-text">当前平台暂无需求贴</p>
</div>
) : (
<div className="request-cards">
{allRequests.map((request) => (
<div key={request.requestid} className="request-card">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
<div className="flex-1 min-w-0">
<h3 className="request-card-title">{request.name}</h3>
<div className="request-card-money">¥{request.money}</div>
</div>
<div className="request-user-info-container">
{renderUserInfo(request.userid, '创建者')}
{request.loaduser && (
<>
<div className="request-user-divider"></div>
{renderUserInfo(request.loaduser, '接管者')}
</>
)}
</div>
</div>
<div className="request-card-content">
{request.plot}
</div>
<div className="request-card-meta">
{request.year && (
<div className="request-meta-item">
<span className="request-meta-label">年份:</span>
<span>{request.year}</span>
</div>
)}
{request.country && (
<div className="request-meta-item">
<span className="request-meta-label">地区:</span>
<span>{request.country}</span>
</div>
)}
<div className="request-meta-item">
<span className="request-meta-label">发布时间:</span>
<span>{new Date(request.requestTime).toLocaleString()}</span>
</div>
</div>
{request.photo && (
<div className="request-card-image-container">
<img
src={`http://localhost:8080${request.photo}`}
alt="需求贴配图"
className="request-card-image"
/>
</div>
)}
<div className="request-card-actions">
{renderActions(request)}
</div>
</div>
))}
</div>
)}
</div>
)}
</div>
);
};
export default RequestBoard;