You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.9 KiB
4.9 KiB
附件上传功能"Failed to create attachment"问题修复详细说明
问题现象
当创建任务并添加附件时,显示"Failed to create attachment"错误。
问题分析
1. 原始问题定位
- 前端设置了
:auto-upload="false",需要手动触发上传 - 上传成功后的数据处理可能存在字段匹配问题
- 附件关联到任务的API调用可能失败
2. 数据流分析
后端 UploadFile API 响应格式:
{
"code": 200,
"message": "File uploaded successfully",
"data": {
"filename": "1736303317123456789_test.pdf",
"filepath": "./uploads/1736303317123456789_test.pdf",
"size": 12345,
"mime_type": "application/pdf"
}
}
后端 TaskAttachment 模型字段:
type TaskAttachment struct {
ID uint `json:"id"`
TaskID uint `json:"task_id"`
FileName string `json:"file_name"` // 注意这里是下划线格式
FilePath string `json:"file_path"`
FileSize int64 `json:"file_size"`
FileType string `json:"file_type"`
UploadedBy uint `json:"uploaded_by"`
CreatedAt time.Time `json:"created_at"`
}
修复方案
1. 增强前端上传成功处理
const handleUploadSuccess = (response: any, file: any, fileList: any[]) => {
console.log('Upload success - raw response:', response)
// 检查响应格式
if (!response || !response.data) {
ElMessage.error('文件上传响应格式错误')
return
}
ElMessage.success('文件上传成功')
// 将上传成功的文件信息添加到taskForm.attachments
const attachmentData = {
file_name: response.data.filename || file.name, // ✓ 字段匹配
file_path: response.data.filepath || response.data.path || '',
file_size: response.data.size || file.size || 0,
file_type: response.data.mime_type || file.type || ''
}
taskForm.attachments.push(attachmentData)
}
2. 优化文件上传时机控制
const saveTask = async () => {
// 检查是否有需要上传的文件
const hasUnuploadedFiles = fileList.value.some((file: any) => !file.response)
if (hasUnuploadedFiles) {
console.log('Found unuploaded files, uploading...')
if (uploadRef.value) {
await uploadRef.value.submit()
// 等待确保上传完成
await new Promise(resolve => setTimeout(resolve, 1000))
}
}
// 创建任务...
// 然后处理附件关联...
}
3. 增强附件关联错误处理
// 如果有附件,需要关联到任务
if (taskForm.attachments && taskForm.attachments.length > 0) {
for (let i = 0; i < taskForm.attachments.length; i++) {
const attachment = taskForm.attachments[i]
try {
await taskApi.addTaskAttachment(taskId, {
file_name: attachment.file_name,
file_path: attachment.file_path,
file_size: attachment.file_size,
file_type: attachment.file_type,
uploaded_by: 1
})
} catch (attachmentError: any) {
// 详细错误处理,附件失败不影响主任务创建
let errorMsg = `附件 "${attachment.file_name}" 添加失败`
if (attachmentError.response?.data?.message) {
errorMsg += `: ${attachmentError.response.data.message}`
}
ElMessage.warning(errorMsg)
}
}
}
4. 改进文件移除处理
const handleFileRemove = (file: any, fileList: any[]) => {
const index = taskForm.attachments.findIndex(
(attachment: any) => {
const uploadedFileName = file.response?.data?.filename || file.name
return attachment.file_name === uploadedFileName
}
)
if (index > -1) {
taskForm.attachments.splice(index, 1)
}
}
测试方法
1. 基本附件上传测试
- 启动前后端服务器
- 访问 http://localhost:5173/tasks
- 点击"创建任务"
- 填写基本信息,拖拽文件到上传区域
- 点击"确定"创建任务
- 观察控制台调试信息和网络请求
2. 异常情况测试
- 测试大文件上传
- 测试不支持的文件格式
- 测试网络中断情况
- 测试后端服务异常情况
3. 调试信息
修复后的代码会在浏览器控制台输出详细调试信息:
- 上传成功时的原始响应
- 构造的附件数据
- 任务创建成功后的ID
- 每个附件的关联结果
关键改进点
- 响应格式验证:增加了对上传响应格式的检查
- 字段映射确认:确保前端构造的数据与后端模型字段一致
- 错误隔离:附件添加失败不影响主任务创建
- 调试增强:添加了详细的调试日志
- 时序控制:确保文件上传完成后再进行任务创建
预期结果
修复后,创建带附件的任务应该:
- 文件正常上传到服务器
- 任务创建成功
- 附件正确关联到任务
- 即使个别附件失败,也不影响整体流程
- 用户得到明确的成功/失败反馈