diff --git a/backend/src/contests/works/dto/submit-work.dto.ts b/backend/src/contests/works/dto/submit-work.dto.ts index e0bd917..1541396 100644 --- a/backend/src/contests/works/dto/submit-work.dto.ts +++ b/backend/src/contests/works/dto/submit-work.dto.ts @@ -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 { @IsInt() @@ -28,5 +45,11 @@ export class SubmitWorkDto { @IsObject() @IsOptional() aiModelMeta?: any; + + @IsArray() + @ValidateNested({ each: true }) + @Type(() => AttachmentDto) + @IsOptional() + attachments?: AttachmentDto[]; } diff --git a/backend/src/contests/works/works.service.ts b/backend/src/contests/works/works.service.ts index 2c92a1b..87122fe 100644 --- a/backend/src/contests/works/works.service.ts +++ b/backend/src/contests/works/works.service.ts @@ -120,28 +120,54 @@ export class WorksService { creator: submitterUserId, }; - return this.prisma.contestWork.create({ - data, - include: { - contest: { - select: { - id: true, - contestName: true, + // 使用事务创建作品和附件 + return this.prisma.$transaction(async (tx) => { + const work = await tx.contestWork.create({ + data, + }); + + // 创建附件记录 + 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: { - include: { - user: { - select: { - id: true, - username: true, - nickname: true, + registration: { + include: { + user: { + select: { + id: true, + username: true, + nickname: true, + }, }, }, }, + attachments: true, }, - attachments: true, - }, + }); }); } diff --git a/frontend/src/api/contests.ts b/frontend/src/api/contests.ts index 1f591ef..5244f60 100644 --- a/frontend/src/api/contests.ts +++ b/frontend/src/api/contests.ts @@ -367,6 +367,13 @@ export interface ContestWorkAttachment { modifyTime?: string; } +export interface SubmitWorkAttachment { + fileName: string; + fileUrl: string; + fileType?: string; + size?: string; +} + export interface SubmitWorkForm { registrationId: number; title: string; @@ -375,6 +382,7 @@ export interface SubmitWorkForm { previewUrl?: string; previewUrls?: string[]; aiModelMeta?: any; + attachments?: SubmitWorkAttachment[]; } export interface QueryWorkParams extends PaginationParams { diff --git a/frontend/src/views/contests/components/SubmitWorkDrawer.vue b/frontend/src/views/contests/components/SubmitWorkDrawer.vue index a948857..4d26056 100644 --- a/frontend/src/views/contests/components/SubmitWorkDrawer.vue +++ b/frontend/src/views/contests/components/SubmitWorkDrawer.vue @@ -553,7 +553,6 @@ const handleSubmit = async () => { let modelFiles: string[] = [] let previewUrl = "" let previewUrlsList: string[] = [] - const attachmentUrls: string[] = [] 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) { try { 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) { console.error("附件上传失败:", error) } @@ -625,9 +635,10 @@ const handleSubmit = async () => { registrationId: registrationIdRef.value, title: form.title, description: form.description, - files: [...modelFiles, ...attachmentUrls], + files: modelFiles, // 只包含模型文件,不包含附件 previewUrl: previewUrl, previewUrls: previewUrlsList.length > 0 ? previewUrlsList : undefined, + attachments: attachments.length > 0 ? attachments : undefined, } await worksApi.submit(submitData)