blob: c347686892c669b0fb12e18198a59a7ab5fd57bf [file] [log] [blame]
崔向南464e19d2025-06-05 17:46:27 +08001import React, { useState, useEffect } from 'react';
2import { Form, Input, Select, Button, Upload, message } from 'antd';
3import axios from 'axios'; // 新增 axios 导入
4import { submitBountyReply, uploadBountyAttachment } from '@/services/bounty/bounty'; // ✅ 新增导入上传接口
5const { Option } = Select;
6interface BountyReplyProps {
7 bountyId: number; // 需要回复的悬赏ID
8 onSuccess?: () => void; // 提交成功回调
9 onCancel?: () => void; // 取消操作回调
10}
11
12const BountyReply: React.FC<BountyReplyProps> = ({
13 bountyId,
14 onSuccess,
15 onCancel
16 }) => {
17 const [form] = Form.useForm();
18 const [bountyList, setBountyList] = useState<{ id: number; title: string }[]>([]);
19 const [uploading, setUploading] = useState(false); // ✅ 新增上传状态
20 // 加载可回复的悬赏列表(修改请求方式)
21 useEffect(() => {
22 const loadBountyList = async () => {
23 try {
24 const res = await axios.get('/api/bounties', { params: { status: 0 } }); // 替换 get 为 axios.get
25 if (res.data.code === 200) {
26 setBountyList(res.data.data.records || []);
27 }
28 } catch (err) {
29 message.error('加载悬赏列表失败');
30 }
31 };
32 loadBountyList();
33 }, []);
34
35 // 附件上传逻辑(修改请求方式)
36 const handleUpload = async (file: File) => {
37 try {
38 setUploading(true);
39 // 1. 上传文件获取路径
40 const filePath = await uploadBountyAttachment(file);
41 // 2. 保存文件对象到表单(用于后续提交)
42 form.setFieldsValue({ attachment: filePath, file }); // ✅ 同时保存路径和文件对象
43 return { url: filePath };
44 } catch (err) {
45 message.error('上传失败');
46 return { error: new Error('上传失败') };
47 } finally {
48 setUploading(false);
49 }
50 };
51
52 // 提交回复逻辑(修改请求方式)
53 // ✅ 替换 axios 请求为服务方法调用
54 const handleSubmit = async (values: { content: string; attachment?: string }) => {
55 try {
56 // 从表单获取文件对象(需在 handleUpload 中保存)
57 const file = form.getFieldValue('file'); // ✅ 获取文件对象
58
59 const res = await submitBountyReply({
60 bountyId,
61 ...values,
62 file, // ✅ 传递文件对象
63 });
64
65 if (res?.code === 200) {
66 message.success('提交成功');
67 form.resetFields();
68 onSuccess?.();
69 } else {
70 throw new Error('接口异常: ' + JSON.stringify(res));
71 }
72 } catch (err) {
73 console.error('提交失败:', err);
74 message.error('提交失败,请重试');
75 }
76 };
77
78 // @ts-ignore
79 // @ts-ignore
80 // @ts-ignore
81 // @ts-ignore
82 // @ts-ignore
83 // @ts-ignore
84 return (
85 <div className="page-container">
86 <h2>回复悬赏</h2>
87 <Form
88 form={form}
89 layout="vertical"
90 onFinish={handleSubmit}
91 requiredMark="optional"
92 style={{ maxWidth: 600 }}
93 >
94 {/* 选择悬赏(默认选中传入的bountyId) */}
95 <Form.Item
96 name="bountyId"
97 label="选择悬赏"
98 rules={[{ required: true, message: '请选择要回复的悬赏' }]}
99 initialValue={bountyId}
100 >
101 <Select disabled={!!bountyId} placeholder="请选择要回复的悬赏">
102 {bountyList.map((item) => (
103 <Option key={item.id} value={item.id}>
104 {item.title}
105 </Option>
106 ))}
107 </Select>
108 </Form.Item>
109
110 {/* 回复内容(保持原有逻辑) */}
111 <Form.Item
112 name="content"
113 label="回复内容"
114 rules={[{ required: true, message: '请输入回复内容' }]}
115 >
116 <Input.TextArea rows={4} placeholder="请输入回复内容" />
117 </Form.Item>
118
119 {/* 附件上传(保持原有逻辑) */}
120 <Form.Item name="attachment" label="附件上传">
121 <Upload
122 customRequest={({ file, onSuccess, onError }) => {
123 handleUpload(file as File); // 显式断言 file 为 File 类型
124 }} // 使用服务层上传
125 maxCount={1}
126 accept=".doc,.docx,.pdf,.zip"
127 showUploadList={false} // 隐藏默认上传列表
128 >
129 <Button loading={uploading}>上传附件</Button>
130 </Upload>
131 </Form.Item>
132
133 {/* 提交按钮 */}
134 <Form.Item>
135 <Button type="primary" htmlType="submit">
136 提交回复
137 </Button>
138 <Button
139 type="default"
140 onClick={() => {
141 form.resetFields();
142 onCancel?.(); // 🔥 取消时触发回调
143 }}
144 style={{ marginLeft: 16 }}
145 >
146 取消
147 </Button>
148 </Form.Item>
149 </Form>
150 </div>
151 );
152};
153
154export default BountyReply;