| import React, { useState, useEffect } from 'react'; |
| import { Table, Button, message, Space, Modal } from 'antd'; |
| import axios from 'axios'; // 新增 axios 导入 |
| import { useNavigate } from 'umi'; |
| |
| import { getBountyList } from '@/services/bounty/bounty'; |
| import BountyPublish from './BountyPublish'; |
| import BountyReply from './BountyReply'; |
| const BountyList: React.FC = () => { |
| const [dataSource, setDataSource] = useState<API.Bounty[]>([]); |
| const [loading, setLoading] = useState(false); |
| const [publishVisible, setPublishVisible] = useState(false); |
| const [replyVisible, setReplyVisible] = useState(false); |
| const [selectedId, setSelectedId] = useState<number | null>(null); |
| |
| const navigate = useNavigate(); |
| |
| // 加载悬赏列表(修改请求方式) |
| |
| const loadBountyList = async () => { |
| try { |
| setLoading(true); |
| const res = await getBountyList(); |
| |
| // 添加详细日志输出 |
| console.log('接口原始响应:', res); |
| |
| // 修改数据处理逻辑以适配实际数据结构 |
| if (res && Array.isArray(res)) { |
| // 当接口直接返回数组时 |
| setDataSource(res); |
| } else if (res && res.code === 200) { |
| // 当接口返回标准分页结构时 |
| setDataSource(res.data.records || res.data || []); |
| } else { |
| throw new Error('接口返回异常结构'); |
| } |
| } catch (err) { |
| console.error('加载数据异常:', err); |
| console.error('完整错误:', err); |
| |
| // 添加网络错误处理 |
| // @ts-ignore |
| if (err?.response?.status === 401) { |
| message.error('认证失效,请重新登录'); |
| navigate('/login'); |
| } else { |
| message.error('加载悬赏列表失败'); |
| } |
| } finally { |
| setLoading(false); |
| } |
| }; |
| |
| useEffect(() => { |
| loadBountyList(); |
| }, []); |
| |
| // ✅ 发布成功回调(普通函数,无需useEffect) |
| const handlePublishSuccess = () => { |
| setPublishVisible(false); |
| loadBountyList(); // 重新加载数据 |
| message.success('悬赏发布成功'); |
| }; |
| |
| // ✅ 回复成功回调(普通函数,无需useEffect) |
| const handleReplySuccess = () => { |
| setReplyVisible(false); |
| loadBountyList(); // 重新加载数据 |
| message.success('回复提交成功'); |
| }; |
| |
| |
| // 跳转详情页 |
| const goDetail = (id: number) => { |
| navigate(`/bounty/detail/${id}`); |
| }; |
| |
| // 表格列配置 |
| const columns = [ |
| { |
| title: '标题', |
| dataIndex: 'title', |
| width: 200, |
| ellipsis: true, |
| }, |
| { |
| title: '发布者ID', |
| dataIndex: 'creator_id', // ✅ 新增列 |
| width: 100, |
| align: 'center' as const, |
| }, |
| { |
| title: '奖励', |
| dataIndex: 'reward', |
| width: 100, |
| align: 'center' as const, |
| }, |
| { |
| title: '状态', |
| dataIndex: 'status', |
| width: 100, |
| render: (status: number) => ( |
| status === 0 ? '未回复' : status === 1 ? '已回复' : '已关闭' |
| ) |
| }, |
| { |
| title: '操作', |
| width: 160, |
| render: (value: unknown, record: API.Bounty) => ( |
| <Space> |
| <Button |
| type="link" |
| onClick={() => navigate(`/bounty/detail/${record.id}`)} |
| > |
| 查看详情 |
| </Button> |
| <Button |
| type="link" |
| onClick={() => { |
| setSelectedId(record.id); |
| setReplyVisible(true); |
| }} |
| > |
| 回复悬赏 |
| </Button> |
| </Space> |
| ) |
| } |
| ]; |
| |
| return ( |
| <div className="page-container"> |
| {/* 顶部操作区 */} |
| <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}> |
| <h2>悬赏列表</h2> |
| {/* 发布按钮 */} |
| <Button |
| type="primary" |
| onClick={() => setPublishVisible(true)} |
| > |
| 发布悬赏 |
| </Button> |
| </div> |
| |
| {/* 悬赏列表 */} |
| <Table |
| dataSource={dataSource} |
| columns={columns} |
| rowKey="id" |
| pagination={{ pageSize: 10 }} |
| loading={loading} |
| /> |
| |
| {/* 发布悬赏模态框 */} |
| <Modal |
| title="发布新悬赏" |
| open={publishVisible} |
| onCancel={() => setPublishVisible(false)} |
| footer={null} |
| > |
| <BountyPublish onSuccess={handlePublishSuccess} /> |
| </Modal> |
| |
| {/* 回复悬赏模态框 */} |
| <Modal |
| title="回复悬赏" |
| open={replyVisible} |
| onCancel={() => setReplyVisible(false)} |
| footer={null} |
| > |
| {selectedId && ( |
| <BountyReply |
| bountyId={selectedId} |
| onSuccess={handleReplySuccess} |
| /> |
| )} |
| </Modal> |
| </div> |
| ); |
| }; |
| |
| export default BountyList; |