R19/R20: 项目主域进 OA 并打通报销差旅周报待办
这个提交包含在:
+11
-2
@@ -19,6 +19,7 @@ const CREATE_SCHEMA = z.object({
|
||||
dueDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional(),
|
||||
priority: z.enum(["low", "normal", "high"]).optional(),
|
||||
source: z.enum(["manual", "weekly_report"]).optional(),
|
||||
projectId: UUID_SCHEMA.nullable().optional(),
|
||||
}).strict();
|
||||
const PATCH_SCHEMA = z.object({
|
||||
title: z.string().trim().min(1).max(200).optional(),
|
||||
@@ -27,6 +28,7 @@ const PATCH_SCHEMA = z.object({
|
||||
dueDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional(),
|
||||
priority: z.enum(["low", "normal", "high"]).optional(),
|
||||
status: z.enum(["todo", "doing", "done", "cancelled"]).optional(),
|
||||
projectId: UUID_SCHEMA.nullable().optional(),
|
||||
}).strict().refine((value) => Object.keys(value).length > 0, { message: "empty_patch" });
|
||||
|
||||
function buildValidationError(details, statusCode = 400) {
|
||||
@@ -60,11 +62,13 @@ function mapTodo(row) {
|
||||
priority: row.priority,
|
||||
status: row.status,
|
||||
source: row.source,
|
||||
projectId: row.project_id ?? null,
|
||||
createdAt: row.created_at?.toISOString?.() ?? null,
|
||||
updatedAt: row.updated_at?.toISOString?.() ?? null,
|
||||
completedAt: row.completed_at?.toISOString?.() ?? null,
|
||||
assignee: row.assignee ? { id: row.assignee.id, employeeNo: row.assignee.employee_no, name: row.assignee.name } : null,
|
||||
creator: row.creator ? { id: row.creator.id, employeeNo: row.creator.employee_no, name: row.creator.name } : null,
|
||||
project: row.project ? { id: row.project.id, projectNo: row.project.project_no, name: row.project.name } : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -122,6 +126,7 @@ async function todosRoutes(fastify) {
|
||||
include: {
|
||||
assignee: { select: { id: true, employee_no: true, name: true } },
|
||||
creator: { select: { id: true, employee_no: true, name: true } },
|
||||
project: { select: { id: true, project_no: true, name: true } },
|
||||
},
|
||||
});
|
||||
return sendData(reply, request, { items: rows.map(mapTodo) });
|
||||
@@ -144,10 +149,12 @@ async function todosRoutes(fastify) {
|
||||
priority: body.priority ?? "normal",
|
||||
status: "todo",
|
||||
source: body.source ?? "manual",
|
||||
project_id: body.projectId ?? null,
|
||||
},
|
||||
include: {
|
||||
assignee: { select: { id: true, employee_no: true, name: true } },
|
||||
creator: { select: { id: true, employee_no: true, name: true } },
|
||||
project: { select: { id: true, project_no: true, name: true } },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -188,11 +195,13 @@ async function todosRoutes(fastify) {
|
||||
...(body.assigneeEmployeeId !== undefined ? { assignee_employee_id: body.assigneeEmployeeId } : {}),
|
||||
...(body.dueDate !== undefined ? { due_date: body.dueDate ? new Date(`${body.dueDate}T00:00:00.000Z`) : null } : {}),
|
||||
...(body.priority !== undefined ? { priority: body.priority } : {}),
|
||||
...(body.projectId !== undefined ? { project_id: body.projectId ?? null } : {}),
|
||||
...(body.status !== undefined ? { status: body.status, completed_at: body.status === "done" ? new Date() : body.status === "cancelled" ? current.completed_at : null } : {}),
|
||||
},
|
||||
include: {
|
||||
assignee: { select: { id: true, employee_no: true, name: true } },
|
||||
creator: { select: { id: true, employee_no: true, name: true } },
|
||||
project: { select: { id: true, project_no: true, name: true } },
|
||||
},
|
||||
});
|
||||
return sendData(reply, request, { item: mapTodo(updated) });
|
||||
@@ -211,7 +220,7 @@ async function todosRoutes(fastify) {
|
||||
const updated = await fastify.prisma.todoItem.update({
|
||||
where: { id: todoId },
|
||||
data: { status: "done", completed_at: new Date() },
|
||||
include: { assignee: { select: { id: true, employee_no: true, name: true } }, creator: { select: { id: true, employee_no: true, name: true } } },
|
||||
include: { assignee: { select: { id: true, employee_no: true, name: true } }, creator: { select: { id: true, employee_no: true, name: true } }, project: { select: { id: true, project_no: true, name: true } } },
|
||||
});
|
||||
return sendData(reply, request, { item: mapTodo(updated) });
|
||||
});
|
||||
@@ -229,7 +238,7 @@ async function todosRoutes(fastify) {
|
||||
const updated = await fastify.prisma.todoItem.update({
|
||||
where: { id: todoId },
|
||||
data: { status: "cancelled", completed_at: null },
|
||||
include: { assignee: { select: { id: true, employee_no: true, name: true } }, creator: { select: { id: true, employee_no: true, name: true } } },
|
||||
include: { assignee: { select: { id: true, employee_no: true, name: true } }, creator: { select: { id: true, employee_no: true, name: true } }, project: { select: { id: true, project_no: true, name: true } } },
|
||||
});
|
||||
return sendData(reply, request, { item: mapTodo(updated) });
|
||||
});
|
||||
|
||||
在新工单中引用
屏蔽一个用户