修复作品附件上传和显示功能
1. 后端 DTO 添加 attachments 字段 2. 后端 submit 方法使用事务创建作品和附件记录 3. 前端 SubmitWorkForm 添加 attachments 类型 4. 前端上传时将附件信息单独传递(不再合并到 files 中) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1010c764cc
commit
9f22a20a2a
@ -1,4 +1,21 @@
|
|||||||
import { IsString, IsInt, IsOptional, IsObject, IsArray } from 'class-validator';
|
import { IsString, IsInt, IsOptional, IsObject, IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class AttachmentDto {
|
||||||
|
@IsString()
|
||||||
|
fileName: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
fileUrl: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
fileType?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
size?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class SubmitWorkDto {
|
export class SubmitWorkDto {
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@ -28,5 +45,11 @@ export class SubmitWorkDto {
|
|||||||
@IsObject()
|
@IsObject()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
aiModelMeta?: any;
|
aiModelMeta?: any;
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => AttachmentDto)
|
||||||
|
@IsOptional()
|
||||||
|
attachments?: AttachmentDto[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -120,28 +120,54 @@ export class WorksService {
|
|||||||
creator: submitterUserId,
|
creator: submitterUserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.prisma.contestWork.create({
|
// 使用事务创建作品和附件
|
||||||
data,
|
return this.prisma.$transaction(async (tx) => {
|
||||||
include: {
|
const work = await tx.contestWork.create({
|
||||||
contest: {
|
data,
|
||||||
select: {
|
});
|
||||||
id: true,
|
|
||||||
contestName: true,
|
// 创建附件记录
|
||||||
|
if (submitWorkDto.attachments && submitWorkDto.attachments.length > 0) {
|
||||||
|
for (const attachment of submitWorkDto.attachments) {
|
||||||
|
await tx.contestWorkAttachment.create({
|
||||||
|
data: {
|
||||||
|
tenantId,
|
||||||
|
contestId: registration.contestId,
|
||||||
|
workId: work.id,
|
||||||
|
fileName: attachment.fileName,
|
||||||
|
fileUrl: attachment.fileUrl,
|
||||||
|
fileType: attachment.fileType,
|
||||||
|
size: attachment.size,
|
||||||
|
creator: submitterUserId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回完整的作品信息
|
||||||
|
return tx.contestWork.findUnique({
|
||||||
|
where: { id: work.id },
|
||||||
|
include: {
|
||||||
|
contest: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
contestName: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
registration: {
|
||||||
registration: {
|
include: {
|
||||||
include: {
|
user: {
|
||||||
user: {
|
select: {
|
||||||
select: {
|
id: true,
|
||||||
id: true,
|
username: true,
|
||||||
username: true,
|
nickname: true,
|
||||||
nickname: true,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
attachments: true,
|
||||||
},
|
},
|
||||||
attachments: true,
|
});
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -367,6 +367,13 @@ export interface ContestWorkAttachment {
|
|||||||
modifyTime?: string;
|
modifyTime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SubmitWorkAttachment {
|
||||||
|
fileName: string;
|
||||||
|
fileUrl: string;
|
||||||
|
fileType?: string;
|
||||||
|
size?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SubmitWorkForm {
|
export interface SubmitWorkForm {
|
||||||
registrationId: number;
|
registrationId: number;
|
||||||
title: string;
|
title: string;
|
||||||
@ -375,6 +382,7 @@ export interface SubmitWorkForm {
|
|||||||
previewUrl?: string;
|
previewUrl?: string;
|
||||||
previewUrls?: string[];
|
previewUrls?: string[];
|
||||||
aiModelMeta?: any;
|
aiModelMeta?: any;
|
||||||
|
attachments?: SubmitWorkAttachment[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryWorkParams extends PaginationParams {
|
export interface QueryWorkParams extends PaginationParams {
|
||||||
|
|||||||
@ -553,7 +553,6 @@ const handleSubmit = async () => {
|
|||||||
let modelFiles: string[] = []
|
let modelFiles: string[] = []
|
||||||
let previewUrl = ""
|
let previewUrl = ""
|
||||||
let previewUrlsList: string[] = []
|
let previewUrlsList: string[] = []
|
||||||
const attachmentUrls: string[] = []
|
|
||||||
|
|
||||||
if (uploadMode.value === "history") {
|
if (uploadMode.value === "history") {
|
||||||
// 从创作历史选择模式
|
// 从创作历史选择模式
|
||||||
@ -611,11 +610,22 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传附件
|
// 上传附件并收集附件信息
|
||||||
|
const attachments: Array<{
|
||||||
|
fileName: string
|
||||||
|
fileUrl: string
|
||||||
|
fileType?: string
|
||||||
|
size?: string
|
||||||
|
}> = []
|
||||||
for (const file of form.attachmentFiles) {
|
for (const file of form.attachmentFiles) {
|
||||||
try {
|
try {
|
||||||
const url = await uploadFile(file)
|
const url = await uploadFile(file)
|
||||||
attachmentUrls.push(url)
|
attachments.push({
|
||||||
|
fileName: file.name,
|
||||||
|
fileUrl: url,
|
||||||
|
fileType: file.type || undefined,
|
||||||
|
size: String(file.size),
|
||||||
|
})
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("附件上传失败:", error)
|
console.error("附件上传失败:", error)
|
||||||
}
|
}
|
||||||
@ -625,9 +635,10 @@ const handleSubmit = async () => {
|
|||||||
registrationId: registrationIdRef.value,
|
registrationId: registrationIdRef.value,
|
||||||
title: form.title,
|
title: form.title,
|
||||||
description: form.description,
|
description: form.description,
|
||||||
files: [...modelFiles, ...attachmentUrls],
|
files: modelFiles, // 只包含模型文件,不包含附件
|
||||||
previewUrl: previewUrl,
|
previewUrl: previewUrl,
|
||||||
previewUrls: previewUrlsList.length > 0 ? previewUrlsList : undefined,
|
previewUrls: previewUrlsList.length > 0 ? previewUrlsList : undefined,
|
||||||
|
attachments: attachments.length > 0 ? attachments : undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
await worksApi.submit(submitData)
|
await worksApi.submit(submitData)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user