diff --git a/backend/community/views.py b/backend/community/views.py
index 5511cc4..6361dcd 100644
--- a/backend/community/views.py
+++ b/backend/community/views.py
@@ -343,6 +343,8 @@ class ReplyViewSet(viewsets.ModelViewSet):
return Response({'liked': liked, 'count': obj.likes.count()})
import requests
+import warnings
+warnings.filterwarnings('ignore', message='Unverified HTTPS request')
class TopicMediaViewSet(viewsets.ViewSet):
"""
@@ -367,7 +369,8 @@ class TopicMediaViewSet(viewsets.ViewSet):
try:
# 这里的 headers 不需要 Content-Type,requests 会自动设置 multipart/form-data
- response = requests.post(upload_url, files=files, timeout=30)
+ # 注意: verify=False 跳过SSL证书验证(data.tangledup-ai.com 证书已过期)
+ response = requests.post(upload_url, files=files, timeout=30, verify=False)
if response.status_code == 200:
data = response.json()
diff --git a/frontend/src/components/competition/ProjectSubmission.jsx b/frontend/src/components/competition/ProjectSubmission.jsx
index cbd52fd..101f8d1 100644
--- a/frontend/src/components/competition/ProjectSubmission.jsx
+++ b/frontend/src/components/competition/ProjectSubmission.jsx
@@ -31,6 +31,9 @@ const ProjectSubmission = ({ competitionId, initialValues, onCancel, onSuccess }
const [form] = Form.useForm();
const [uploadedFiles, setUploadedFiles] = useState([]);
const [uploadingFiles, setUploadingFiles] = useState({});
+ const [pendingCoverImage, setPendingCoverImage] = useState(null);
+ const [pendingAttachments, setPendingAttachments] = useState([]);
+ const [isCreatingProject, setIsCreatingProject] = useState(false);
const queryClient = useQueryClient();
useEffect(() => {
@@ -66,30 +69,6 @@ const ProjectSubmission = ({ competitionId, initialValues, onCancel, onSuccess }
}
}, [initialValues, form]);
- const createMutation = useMutation({
- mutationFn: createProject,
- onSuccess: () => {
- message.success('项目创建成功');
- queryClient.invalidateQueries(['projects']);
- onSuccess();
- },
- onError: (error) => {
- message.error(`创建失败: ${error.response?.data?.detail || error.message}`);
- }
- });
-
- const updateMutation = useMutation({
- mutationFn: (data) => updateProject(initialValues.id, data),
- onSuccess: () => {
- message.success('项目更新成功');
- queryClient.invalidateQueries(['projects']);
- onSuccess();
- },
- onError: (error) => {
- message.error(`更新失败: ${error.response?.data?.detail || error.message}`);
- }
- });
-
const handleUpload = ({ file, onSuccess, onError }) => {
console.log('handleUpload called', file.name);
@@ -144,17 +123,80 @@ const ProjectSubmission = ({ competitionId, initialValues, onCancel, onSuccess }
});
};
- const onFinish = (values) => {
+ const uploadPendingFiles = async (projectId) => {
+ const uploadedFilesList = [];
+
+ if (pendingCoverImage) {
+ try {
+ const formData = new FormData();
+ formData.append('file', pendingCoverImage);
+ const res = await uploadProjectFile(formData);
+ const imageUrl = res.data.file_url_display || res.data.file_url;
+ await updateProject(projectId, { cover_image_url: imageUrl });
+ setPendingCoverImage(null);
+ } catch (err) {
+ console.error('封面上传失败:', err);
+ }
+ }
+
+ for (const file of pendingAttachments) {
+ try {
+ const formData = new FormData();
+ formData.append('file', file);
+ formData.append('project', projectId);
+ const res = await uploadProjectFile(formData);
+ uploadedFilesList.push({
+ uid: res.data.id,
+ id: res.data.id,
+ name: res.data.name || file.name,
+ url: res.data.file_url_display || res.data.file_url,
+ fileType: res.data.file_type,
+ status: 'done'
+ });
+ } catch (err) {
+ console.error('文件上传失败:', err);
+ message.error(`文件 ${file.name} 上传失败`);
+ }
+ }
+
+ if (uploadedFilesList.length > 0) {
+ setUploadedFiles(prev => [...prev, ...uploadedFilesList]);
+ }
+ setPendingAttachments([]);
+ };
+
+ const onFinish = async (values) => {
+ setIsCreatingProject(true);
const data = {
...values,
competition: competitionId,
};
if (initialValues?.id) {
- updateMutation.mutate(data);
+ await updateProject(initialValues.id, data);
+ if (pendingAttachments.length > 0) {
+ await uploadPendingFiles(initialValues.id);
+ }
+ message.success('项目更新成功');
+ queryClient.invalidateQueries(['projects']);
+ onSuccess();
} else {
- createMutation.mutate(data);
+ try {
+ const res = await createProject(data);
+ const projectId = res.data.id;
+
+ if (pendingAttachments.length > 0 || pendingCoverImage) {
+ await uploadPendingFiles(projectId);
+ }
+
+ message.success('项目创建成功');
+ queryClient.invalidateQueries(['projects']);
+ onSuccess();
+ } catch (error) {
+ message.error(`创建失败: ${error.response?.data?.detail || error.message}`);
+ }
}
+ setIsCreatingProject(false);
};
return (
@@ -205,12 +247,13 @@ const ProjectSubmission = ({ competitionId, initialValues, onCancel, onSuccess }
label="封面图片"
extra="支持上传本地图片,自动转换为URL"
>
- {initialValues ? (
-