library-picturebook-activity/frontend/src/api/contests.ts

845 lines
20 KiB
TypeScript
Raw Normal View History

2025-12-09 11:10:36 +08:00
import request from "@/utils/request";
import type { PaginationParams, PaginationResponse } from "@/types/api";
// ==================== 比赛相关类型 ====================
export interface Contest {
id: number;
contestName: string;
contestType: "individual" | "team";
contestState: "unpublished" | "published";
startTime: string;
endTime: string;
address?: string;
content?: string;
contestTenants?: number[];
coverUrl?: string;
posterUrl?: string;
contactName?: string;
contactPhone?: string;
contactQrcode?: string;
organizers?: string[];
coOrganizers?: string[];
sponsors?: string[];
registerStartTime: string;
registerEndTime: string;
registerState?: string;
submitRule: "once" | "resubmit";
submitStartTime: string;
submitEndTime: string;
reviewRuleId?: number;
reviewStartTime: string;
reviewEndTime: string;
resultPublishTime?: string;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
attachments?: ContestAttachment[];
reviewRule?: ContestReviewRule;
_count?: {
registrations: number;
works: number;
teams: number;
judges: number;
};
}
export interface CreateContestForm {
contestName: string;
contestType: "individual" | "team";
startTime: string;
endTime: string;
address?: string;
content?: string;
contestTenants?: number[];
coverUrl?: string;
posterUrl?: string;
contactName?: string;
contactPhone?: string;
contactQrcode?: string;
organizers?: string[];
coOrganizers?: string[];
sponsors?: string[];
registerStartTime: string;
registerEndTime: string;
submitRule?: "once" | "resubmit";
submitStartTime: string;
submitEndTime: string;
reviewStartTime: string;
reviewEndTime: string;
resultPublishTime?: string;
}
export interface UpdateContestForm extends Partial<CreateContestForm> {
contestState?: "unpublished" | "published";
}
export interface QueryContestParams extends PaginationParams {
contestName?: string;
contestState?: "unpublished" | "published";
contestType?: string;
}
// ==================== 附件相关类型 ====================
export interface ContestAttachment {
id: number;
contestId: number;
fileName: string;
fileUrl: string;
format?: string;
fileType?: string;
size?: string;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
}
export interface CreateAttachmentForm {
contestId: number;
fileName: string;
fileUrl: string;
format?: string;
fileType?: string;
size?: string;
}
// ==================== 评审规则相关类型 ====================
export interface ContestReviewRule {
id: number;
contestId: number;
ruleName: string;
dimensions: any;
calculationRule: "average" | "max" | "min" | "weighted";
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
}
export interface CreateReviewRuleForm {
contestId: number;
ruleName: string;
dimensions: any;
calculationRule?: "average" | "max" | "min" | "weighted";
}
// ==================== 报名相关类型 ====================
export interface ContestRegistration {
id: number;
contestId: number;
tenantId: number;
registrationType?: "individual" | "team";
teamId?: number;
teamName?: string;
userId: number;
accountNo: string;
accountName: string;
role?: string;
registrationState: "pending" | "passed" | "rejected" | "withdrawn";
registrant?: number;
registrationTime: string;
reason?: string;
operator?: number;
operationDate?: string;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
contest?: Contest;
user?: {
id: number;
username: string;
nickname: string;
};
team?: ContestTeam;
_count?: {
works: number;
};
}
export interface CreateRegistrationForm {
contestId: number;
registrationType: "individual" | "team";
teamId?: number;
userId: number;
}
export interface ReviewRegistrationForm {
registrationState: "pending" | "passed" | "rejected" | "withdrawn";
reason?: string;
}
export interface QueryRegistrationParams extends PaginationParams {
contestId?: number;
registrationState?: "pending" | "passed" | "rejected" | "withdrawn";
registrationType?: string;
userId?: number;
}
// ==================== 团队相关类型 ====================
export interface ContestTeam {
id: number;
tenantId: number;
contestId: number;
teamName: string;
leaderUserId: number;
maxMembers?: number;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
leader?: {
id: number;
username: string;
nickname: string;
};
members?: ContestTeamMember[];
contest?: Contest;
_count?: {
members: number;
registrations: number;
};
}
export interface ContestTeamMember {
id: number;
tenantId: number;
teamId: number;
userId: number;
role: "leader" | "member" | "mentor";
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
user?: {
id: number;
username: string;
nickname: string;
};
}
export interface CreateTeamForm {
contestId: number;
teamName: string;
leaderUserId: number;
maxMembers?: number;
}
export interface InviteMemberForm {
userId: number;
role?: "leader" | "member" | "mentor";
}
// ==================== 作品相关类型 ====================
export interface ContestWork {
id: number;
tenantId: number;
contestId: number;
registrationId: number;
workNo?: string;
title: string;
description?: string;
files?: string[];
version: number;
isLatest: boolean;
status: "submitted" | "locked" | "reviewing" | "rejected" | "accepted";
submitTime: string;
submitterUserId?: number;
submitterAccountNo?: string;
submitSource: string;
previewUrl?: string;
aiModelMeta?: any;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
contest?: Contest;
registration?: ContestRegistration;
attachments?: ContestWorkAttachment[];
_count?: {
scores: number;
assignments: number;
};
}
export interface ContestWorkAttachment {
id: number;
tenantId: number;
contestId: number;
workId: number;
fileName: string;
fileUrl: string;
format?: string;
fileType?: string;
size?: string;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
}
export interface SubmitWorkForm {
registrationId: number;
title: string;
description?: string;
files?: string[];
previewUrl?: string;
aiModelMeta?: any;
}
export interface QueryWorkParams extends PaginationParams {
contestId?: number;
registrationId?: number;
status?: "submitted" | "locked" | "reviewing" | "rejected" | "accepted";
title?: string;
}
// ==================== 评审相关类型 ====================
export interface ContestWorkJudgeAssignment {
id: number;
contestId: number;
workId: number;
judgeId: number;
assignmentTime: string;
status: "assigned" | "reviewing" | "completed";
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
work?: ContestWork;
judge?: {
id: number;
username: string;
nickname: string;
};
scores?: ContestWorkScore[];
}
export interface ContestWorkScore {
id: number;
tenantId: number;
contestId: number;
workId: number;
assignmentId: number;
judgeId: number;
judgeName: string;
dimensionScores: any;
totalScore: number;
comments?: string;
scoreTime: string;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
work?: ContestWork;
judge?: {
id: number;
username: string;
nickname: string;
};
}
export interface AssignWorkForm {
workId: number;
judgeIds: number[];
}
export interface CreateScoreForm {
workId: number;
assignmentId: number;
dimensionScores: any;
totalScore: number;
comments?: string;
}
// ==================== 公告相关类型 ====================
export interface ContestNotice {
id: number;
contestId: number;
title: string;
content: string;
noticeType: "system" | "manual" | "urgent";
priority: number;
publishTime?: string;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
contest?: Contest;
}
export interface CreateNoticeForm {
contestId: number;
title: string;
content: string;
noticeType?: "system" | "manual" | "urgent";
priority?: number;
}
// ==================== 评委相关类型 ====================
export interface ContestJudge {
id: number;
contestId: number;
judgeId: number;
specialty?: string;
weight?: number;
description?: string;
creator?: number;
modifier?: number;
createTime?: string;
modifyTime?: string;
validState?: number;
contest?: Contest;
judge?: {
id: number;
username: string;
nickname: string;
email?: string;
};
_count?: {
assignedContestWorks: number;
scoredContestWorks: number;
};
}
export interface CreateJudgeForm {
contestId: number;
judgeId: number;
specialty?: string;
weight?: number;
description?: string;
}
// ==================== API 函数 ====================
// 比赛管理
export const contestsApi = {
// 获取比赛列表
getList: async (
params: QueryContestParams
): Promise<PaginationResponse<Contest>> => {
const response = await request.get<any, PaginationResponse<Contest>>(
"/contests",
{ params }
);
return response;
},
// 获取比赛详情
getDetail: async (id: number): Promise<Contest> => {
const response = await request.get<any, Contest>(`/contests/${id}`);
return response;
},
// 创建比赛
create: async (data: CreateContestForm): Promise<Contest> => {
const response = await request.post<any, Contest>("/contests", data);
return response;
},
// 更新比赛
update: async (id: number, data: UpdateContestForm): Promise<Contest> => {
const response = await request.patch<any, Contest>(`/contests/${id}`, data);
return response;
},
// 发布/撤回比赛
publish: async (
id: number,
contestState: "unpublished" | "published"
): Promise<Contest> => {
const response = await request.patch<any, Contest>(
`/contests/${id}/publish`,
{ contestState }
);
return response;
},
// 删除比赛
delete: async (id: number): Promise<void> => {
return await request.delete<any, void>(`/contests/${id}`);
},
};
// 附件管理
export const attachmentsApi = {
// 获取比赛附件列表
getList: async (contestId: number): Promise<ContestAttachment[]> => {
const response = await request.get<any, ContestAttachment[]>(
`/contests/attachments/contest/${contestId}`
);
return response;
},
// 创建附件
create: async (data: CreateAttachmentForm): Promise<ContestAttachment> => {
const response = await request.post<any, ContestAttachment>(
"/contests/attachments",
data
);
return response;
},
// 删除附件
delete: async (id: number): Promise<void> => {
return await request.delete<any, void>(`/contests/attachments/${id}`);
},
};
// 评审规则
export const reviewRulesApi = {
// 获取评审规则
getByContest: async (contestId: number): Promise<ContestReviewRule> => {
const response = await request.get<any, ContestReviewRule>(
`/contests/review-rules/contest/${contestId}`
);
return response;
},
// 创建评审规则
create: async (data: CreateReviewRuleForm): Promise<ContestReviewRule> => {
const response = await request.post<any, ContestReviewRule>(
"/contests/review-rules",
data
);
return response;
},
// 更新评审规则
update: async (
contestId: number,
data: Partial<CreateReviewRuleForm>
): Promise<ContestReviewRule> => {
const response = await request.patch<any, ContestReviewRule>(
`/contests/review-rules/contest/${contestId}`,
data
);
return response;
},
};
// 报名管理
export const registrationsApi = {
// 获取报名列表
getList: async (
params: QueryRegistrationParams
): Promise<PaginationResponse<ContestRegistration>> => {
const response = await request.get<
any,
PaginationResponse<ContestRegistration>
>("/contests/registrations", { params });
return response;
},
// 获取报名详情
getDetail: async (id: number): Promise<ContestRegistration> => {
const response = await request.get<any, ContestRegistration>(
`/contests/registrations/${id}`
);
return response;
},
// 创建报名
create: async (
data: CreateRegistrationForm
): Promise<ContestRegistration> => {
const response = await request.post<any, ContestRegistration>(
"/contests/registrations",
data
);
return response;
},
// 审核报名
review: async (
id: number,
data: ReviewRegistrationForm
): Promise<ContestRegistration> => {
const response = await request.patch<any, ContestRegistration>(
`/contests/registrations/${id}/review`,
data
);
return response;
},
// 删除报名
delete: async (id: number): Promise<void> => {
return await request.delete<any, void>(`/contests/registrations/${id}`);
},
};
// 团队管理
export const teamsApi = {
// 获取团队列表
getList: async (contestId: number): Promise<ContestTeam[]> => {
const response = await request.get<any, ContestTeam[]>(
`/contests/teams/contest/${contestId}`
);
return response;
},
// 获取团队详情
getDetail: async (id: number): Promise<ContestTeam> => {
const response = await request.get<any, ContestTeam>(
`/contests/teams/${id}`
);
return response;
},
// 创建团队
create: async (data: CreateTeamForm): Promise<ContestTeam> => {
const response = await request.post<any, ContestTeam>(
"/contests/teams",
data
);
return response;
},
// 更新团队
update: async (
id: number,
data: Partial<CreateTeamForm>
): Promise<ContestTeam> => {
const response = await request.patch<any, ContestTeam>(
`/contests/teams/${id}`,
data
);
return response;
},
// 邀请成员
inviteMember: async (
teamId: number,
data: InviteMemberForm
): Promise<ContestTeamMember> => {
const response = await request.post<any, ContestTeamMember>(
`/contests/teams/${teamId}/members`,
data
);
return response;
},
// 移除成员
removeMember: async (teamId: number, userId: number): Promise<void> => {
return await request.delete<any, void>(
`/contests/teams/${teamId}/members/${userId}`
);
},
// 删除团队
delete: async (id: number): Promise<void> => {
return await request.delete<any, void>(`/contests/teams/${id}`);
},
};
// 作品管理
export const worksApi = {
// 获取作品列表
getList: async (
params: QueryWorkParams
): Promise<PaginationResponse<ContestWork>> => {
const response = await request.get<any, PaginationResponse<ContestWork>>(
"/contests/works",
{ params }
);
return response;
},
// 获取作品详情
getDetail: async (id: number): Promise<ContestWork> => {
const response = await request.get<any, ContestWork>(
`/contests/works/${id}`
);
return response;
},
// 提交作品
submit: async (data: SubmitWorkForm): Promise<ContestWork> => {
const response = await request.post<any, ContestWork>(
"/contests/works/submit",
data
);
return response;
},
// 获取作品版本列表
getVersions: async (registrationId: number): Promise<ContestWork[]> => {
const response = await request.get<any, ContestWork[]>(
`/contests/works/registration/${registrationId}/versions`
);
return response;
},
// 删除作品
delete: async (id: number): Promise<void> => {
return await request.delete<any, void>(`/contests/works/${id}`);
},
};
// 评审管理
export const reviewsApi = {
// 分配作品给评委
assignWork: async (
contestId: number,
data: AssignWorkForm
): Promise<ContestWorkJudgeAssignment[]> => {
const response = await request.post<any, ContestWorkJudgeAssignment[]>(
`/contests/reviews/assign?contestId=${contestId}`,
data
);
return response;
},
// 评分
score: async (data: CreateScoreForm): Promise<ContestWorkScore> => {
const response = await request.post<any, ContestWorkScore>(
"/contests/reviews/score",
data
);
return response;
},
// 更新评分
updateScore: async (
scoreId: number,
data: Partial<CreateScoreForm>
): Promise<ContestWorkScore> => {
const response = await request.patch<any, ContestWorkScore>(
`/contests/reviews/score/${scoreId}`,
data
);
return response;
},
// 获取分配给当前评委的作品
getAssignedWorks: async (
contestId: number
): Promise<ContestWorkJudgeAssignment[]> => {
const response = await request.get<any, ContestWorkJudgeAssignment[]>(
`/contests/reviews/assigned?contestId=${contestId}`
);
return response;
},
// 获取作品评分列表
getWorkScores: async (workId: number): Promise<ContestWorkScore[]> => {
const response = await request.get<any, ContestWorkScore[]>(
`/contests/reviews/work/${workId}/scores`
);
return response;
},
// 计算最终得分
calculateFinalScore: async (
workId: number
): Promise<{
finalScore: number;
scoreCount: number;
calculationRule: string;
}> => {
const response = await request.get<
any,
{ finalScore: number; scoreCount: number; calculationRule: string }
>(`/contests/reviews/work/${workId}/final-score`);
return response;
},
};
// 公告管理
export const noticesApi = {
// 获取公告列表
getList: async (contestId: number): Promise<ContestNotice[]> => {
const response = await request.get<any, ContestNotice[]>(
`/contests/notices/contest/${contestId}`
);
return response;
},
// 获取公告详情
getDetail: async (id: number): Promise<ContestNotice> => {
const response = await request.get<any, ContestNotice>(
`/contests/notices/${id}`
);
return response;
},
// 创建公告
create: async (data: CreateNoticeForm): Promise<ContestNotice> => {
const response = await request.post<any, ContestNotice>(
"/contests/notices",
data
);
return response;
},
// 更新公告
update: async (
id: number,
data: Partial<CreateNoticeForm>
): Promise<ContestNotice> => {
const response = await request.patch<any, ContestNotice>(
`/contests/notices/${id}`,
data
);
return response;
},
// 删除公告
delete: async (id: number): Promise<void> => {
return await request.delete<any, void>(`/contests/notices/${id}`);
},
};
// 评委管理
export const judgesApi = {
// 获取评委列表
getList: async (contestId: number): Promise<ContestJudge[]> => {
const response = await request.get<any, ContestJudge[]>(
`/contests/judges/contest/${contestId}`
);
return response;
},
// 获取评委详情
getDetail: async (id: number): Promise<ContestJudge> => {
const response = await request.get<any, ContestJudge>(
`/contests/judges/${id}`
);
return response;
},
// 添加评委
create: async (data: CreateJudgeForm): Promise<ContestJudge> => {
const response = await request.post<any, ContestJudge>(
"/contests/judges",
data
);
return response;
},
// 更新评委
update: async (
id: number,
data: Partial<CreateJudgeForm>
): Promise<ContestJudge> => {
const response = await request.patch<any, ContestJudge>(
`/contests/judges/${id}`,
data
);
return response;
},
// 删除评委
delete: async (id: number): Promise<void> => {
return await request.delete<any, void>(`/contests/judges/${id}`);
},
};