blob: c347686892c669b0fb12e18198a59a7ab5fd57bf [file] [log] [blame] [edit]
import React, { useState, useEffect } from 'react';
import { Form, Input, Select, Button, Upload, message } from 'antd';
import axios from 'axios'; // 新增 axios 导入
import { submitBountyReply, uploadBountyAttachment } from '@/services/bounty/bounty'; // ✅ 新增导入上传接口
const { Option } = Select;
interface BountyReplyProps {
bountyId: number; // 需要回复的悬赏ID
onSuccess?: () => void; // 提交成功回调
onCancel?: () => void; // 取消操作回调
}
const BountyReply: React.FC<BountyReplyProps> = ({
bountyId,
onSuccess,
onCancel
}) => {
const [form] = Form.useForm();
const [bountyList, setBountyList] = useState<{ id: number; title: string }[]>([]);
const [uploading, setUploading] = useState(false); // ✅ 新增上传状态
// 加载可回复的悬赏列表(修改请求方式)
useEffect(() => {
const loadBountyList = async () => {
try {
const res = await axios.get('/api/bounties', { params: { status: 0 } }); // 替换 get 为 axios.get
if (res.data.code === 200) {
setBountyList(res.data.data.records || []);
}
} catch (err) {
message.error('加载悬赏列表失败');
}
};
loadBountyList();
}, []);
// 附件上传逻辑(修改请求方式)
const handleUpload = async (file: File) => {
try {
setUploading(true);
// 1. 上传文件获取路径
const filePath = await uploadBountyAttachment(file);
// 2. 保存文件对象到表单(用于后续提交)
form.setFieldsValue({ attachment: filePath, file }); // ✅ 同时保存路径和文件对象
return { url: filePath };
} catch (err) {
message.error('上传失败');
return { error: new Error('上传失败') };
} finally {
setUploading(false);
}
};
// 提交回复逻辑(修改请求方式)
// ✅ 替换 axios 请求为服务方法调用
const handleSubmit = async (values: { content: string; attachment?: string }) => {
try {
// 从表单获取文件对象(需在 handleUpload 中保存)
const file = form.getFieldValue('file'); // ✅ 获取文件对象
const res = await submitBountyReply({
bountyId,
...values,
file, // ✅ 传递文件对象
});
if (res?.code === 200) {
message.success('提交成功');
form.resetFields();
onSuccess?.();
} else {
throw new Error('接口异常: ' + JSON.stringify(res));
}
} catch (err) {
console.error('提交失败:', err);
message.error('提交失败,请重试');
}
};
// @ts-ignore
// @ts-ignore
// @ts-ignore
// @ts-ignore
// @ts-ignore
// @ts-ignore
return (
<div className="page-container">
<h2>回复悬赏</h2>
<Form
form={form}
layout="vertical"
onFinish={handleSubmit}
requiredMark="optional"
style={{ maxWidth: 600 }}
>
{/* 选择悬赏(默认选中传入的bountyId) */}
<Form.Item
name="bountyId"
label="选择悬赏"
rules={[{ required: true, message: '请选择要回复的悬赏' }]}
initialValue={bountyId}
>
<Select disabled={!!bountyId} placeholder="请选择要回复的悬赏">
{bountyList.map((item) => (
<Option key={item.id} value={item.id}>
{item.title}
</Option>
))}
</Select>
</Form.Item>
{/* 回复内容(保持原有逻辑) */}
<Form.Item
name="content"
label="回复内容"
rules={[{ required: true, message: '请输入回复内容' }]}
>
<Input.TextArea rows={4} placeholder="请输入回复内容" />
</Form.Item>
{/* 附件上传(保持原有逻辑) */}
<Form.Item name="attachment" label="附件上传">
<Upload
customRequest={({ file, onSuccess, onError }) => {
handleUpload(file as File); // 显式断言 file 为 File 类型
}} // 使用服务层上传
maxCount={1}
accept=".doc,.docx,.pdf,.zip"
showUploadList={false} // 隐藏默认上传列表
>
<Button loading={uploading}>上传附件</Button>
</Upload>
</Form.Item>
{/* 提交按钮 */}
<Form.Item>
<Button type="primary" htmlType="submit">
提交回复
</Button>
<Button
type="default"
onClick={() => {
form.resetFields();
onCancel?.(); // 🔥 取消时触发回调
}}
style={{ marginLeft: 16 }}
>
取消
</Button>
</Form.Item>
</Form>
</div>
);
};
export default BountyReply;