feat: Day 8-9 - Project Management API completed
Backend: - Create project routes (GET, POST, PUT, DELETE) - Implement projectController with CRUD operations - Create projectService for database operations - Add validation middleware for request validation - Update Prisma schema (add background, researchType, deletedAt fields) - Implement soft delete for projects Frontend: - Create projectApi service module - Update useProjectStore with fetchProjects and loading state - Connect ProjectSelector to real API with loading indicator - Connect CreateProjectDialog to real API with error handling - Connect EditProjectDialog to real API with loading state - Add comprehensive error handling and user feedback Build: Both frontend and backend build successfully
This commit is contained in:
110
backend/src/middleware/validateProject.ts
Normal file
110
backend/src/middleware/validateProject.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { FastifyRequest, FastifyReply } from 'fastify';
|
||||
|
||||
interface CreateProjectBody {
|
||||
name: string;
|
||||
background?: string;
|
||||
researchType: 'observational' | 'interventional';
|
||||
}
|
||||
|
||||
interface UpdateProjectBody {
|
||||
name?: string;
|
||||
background?: string;
|
||||
researchType?: 'observational' | 'interventional';
|
||||
}
|
||||
|
||||
// 验证创建项目请求
|
||||
export async function validateProjectCreate(request: FastifyRequest, reply: FastifyReply) {
|
||||
const body = request.body as CreateProjectBody;
|
||||
|
||||
// 验证必填字段
|
||||
if (!body.name || typeof body.name !== 'string') {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '项目名称为必填项',
|
||||
});
|
||||
}
|
||||
|
||||
if (body.name.trim().length === 0) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '项目名称不能为空',
|
||||
});
|
||||
}
|
||||
|
||||
if (body.name.length > 100) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '项目名称不能超过100个字符',
|
||||
});
|
||||
}
|
||||
|
||||
// 验证研究类型
|
||||
if (!body.researchType) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '研究类型为必填项',
|
||||
});
|
||||
}
|
||||
|
||||
if (!['observational', 'interventional'].includes(body.researchType)) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '研究类型必须是observational或interventional',
|
||||
});
|
||||
}
|
||||
|
||||
// 验证项目背景(可选,但有长度限制)
|
||||
if (body.background && body.background.length > 2000) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '项目背景不能超过2000个字符',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 验证更新项目请求
|
||||
export async function validateProjectUpdate(request: FastifyRequest, reply: FastifyReply) {
|
||||
const body = request.body as UpdateProjectBody;
|
||||
|
||||
// 至少需要更新一个字段
|
||||
if (!body.name && !body.background && !body.researchType) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '至少需要提供一个要更新的字段',
|
||||
});
|
||||
}
|
||||
|
||||
// 验证项目名称
|
||||
if (body.name !== undefined) {
|
||||
if (typeof body.name !== 'string' || body.name.trim().length === 0) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '项目名称不能为空',
|
||||
});
|
||||
}
|
||||
|
||||
if (body.name.length > 100) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '项目名称不能超过100个字符',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 验证研究类型
|
||||
if (body.researchType && !['observational', 'interventional'].includes(body.researchType)) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '研究类型必须是observational或interventional',
|
||||
});
|
||||
}
|
||||
|
||||
// 验证项目背景
|
||||
if (body.background && body.background.length > 2000) {
|
||||
return reply.code(400).send({
|
||||
success: false,
|
||||
message: '项目背景不能超过2000个字符',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user