blob: 41a25df04d6f84f583b44bada91ad31056064509 [file] [log] [blame]
import React, { useState, useEffect } from 'react';
import { Button, Descriptions, List, message, Tag } from 'antd';
import axios from 'axios'; // 新增 axios 导入
import { useParams } from 'umi';
import { getBountyDetail, getProfile } from '@/services/bounty/bounty';
import { downloadAttachment,adoptSubmission } from '@/services/bounty/bounty';
const BountyDetail: React.FC = () => {
const [bounty, setBounty] = useState<API.BountyDetail>({} as API.BountyDetail);
const [loading, setLoading] = useState(false); // 新增加载状态
const [currentUserId, setCurrentUserId] = useState<number | null>(null);
console.log('当前用户id:',currentUserId);
console.log('悬赏发布用户id:',bounty.creator_id);
const handleAdoptSubmission = async (submissionId: number, currentStatus: number) => {
console.log('【采纳请求】', {
submissionId,
currentStatus,
bounty: bounty,
currentUserId
});
if (currentStatus === 1) return;
try {
const res = await adoptSubmission(submissionId);
console.log('【采纳响应】', {
status: res.status,
data: res.data,
headers: res.headers
});
if (res.code === 200) {
message.success('采纳成功');
setBounty(prev => {
console.log('【状态更新】', {
old: prev.submissions,
new: prev.submissions?.map(sub =>
sub.id === submissionId ? { ...sub, status: 1 } : sub
)
});
return {
...prev,
submissions: prev.submissions?.map(sub =>
sub.id === submissionId ? { ...sub, status: 1 } : sub
)
};
});
} else {
message.error(`采纳失败: ${res.msg}`);
}
} catch (error: any) {
console.error('【采纳错误】', {
error: error,
response: error.response?.data,
status: error.response?.status
});
message.error(`网络异常: ${error.message}`);
}
};
const handleDownload = async (attachmentPath: string, submissionUserId: number) => {
try {
// ✅ 新增权限校验
if (!currentUserId || (currentUserId !== bounty.creator_id && currentUserId !== submissionUserId)) {
message.error('无权查看此附件');
return;
}
const blob = await downloadAttachment(attachmentPath);
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = attachmentPath.split('/').pop() || 'file';
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
} catch (err) {
message.error('下载附件失败,请重试');
console.error('下载附件失败:', err);
}
};
useEffect(() => {
const fetchProfile = async () => {
try {
const res = await getProfile(); // 调用后端接口
if (res && res.code === 200) {
setCurrentUserId(res.data.userId); // 从接口获取 userId
} else {
message.error('获取用户信息失败');
}
} catch (err) {
console.error('获取用户信息失败:', err);
}
};
fetchProfile();
}, []);
const { id } = useParams<{ id: string }>();
// 修改加载方法(适配统一请求)✅
useEffect(() => {
if (!id) return;
const loadBountyDetail = async () => {
try {
setLoading(true);
const res = await getBountyDetail(id);
console.log('【详情响应】原始数据:', res); // 👈 关键日志
if (res && res.code === 200) {
setBounty(res.data);
// 👇 新增:检查 submissions 数据结构
console.log('【submissions 数据】:', res.data.submissions);
} else {
throw new Error('响应结构异常');
}
} catch (err) {
console.error('【详情请求】错误:', err);
} finally {
setLoading(false);
}
};
loadBountyDetail();
}, [id]);
return (
<div className="page-container">
<h2>悬赏详情</h2>
{/* 基础信息 */}
<Descriptions title="悬赏信息" bordered>
<Descriptions.Item label="标题">{bounty.title}</Descriptions.Item>
<Descriptions.Item label="发布者ID">{bounty.creator_id}</Descriptions.Item> // 新增字段
<Descriptions.Item label="奖励">{bounty.reward}</Descriptions.Item>
<Descriptions.Item label="状态">
{bounty.status === 0 ? '进行中' : bounty.status === 1 ? '已完成' : '已关闭'}
</Descriptions.Item>
<Descriptions.Item label="截止时间">{bounty.deadline}</Descriptions.Item>
<Descriptions.Item label="描述" span={3}>
{bounty.description}
</Descriptions.Item>
</Descriptions>
{/* 回复列表 */}
{bounty.submissions && (
<div style={{ marginTop: 24 }}>
<h3>回复列表</h3>
<List
dataSource={bounty.submissions}
renderItem={(item) => (
<List.Item>
<List.Item.Meta
title={`回复人ID:${item.userId}`}
description={
<>
{item.content}
{/* 状态标签 */}
<span style={{ marginLeft: 16 }}>
{item.status === 1 ? (
<Tag color="green">已采纳</Tag>
) : (
<Tag color="red">未被采纳</Tag>
)}
</span>
</>
}
/>
{/* 发布者操作按钮 */}
{currentUserId === bounty.creator_id && (
<Button
type="primary"
size="small"
onClick={() => handleAdoptSubmission(item.id, item.status)}
disabled={item.status === 1}
>
{item.status === 1 ? '已采纳' : '采纳'}
</Button>
)}
{/* 附件下载 */}
{item.attachment && currentUserId === bounty.creator_id && (
<a onClick={(e) => handleDownload(item.attachment, item.userId)} style={{ marginLeft: 8 }}>
查看附件
</a>
)}
</List.Item>
)}
/>
</div>
)}
</div>
);
};
// 定义类型(建议单独放在src/types.d.ts中)
declare namespace API {
export interface BountyDetail {
id: number;
title: string;
creator_id: number; // ✅ 新增:发布者ID
description: string;
reward: number;
deadline: string;
status: number;
submissions: Array<{
id: number;
userId: number; // ✅ 替换 id 为 userId
username: string;
content: string;
attachment: string;
status: number;
}>;
}
}
export default BountyDetail;