LP6 完善请假采购体验与审批说明

这个提交包含在:
2026-05-12 13:02:00 +08:00
父节点 21887ce28a
当前提交 3d1e4c43f6
共修改 14 个文件,包含 502 行新增和 39 行删除
+81
查看文件
@@ -94,6 +94,46 @@ const LEAVE_TYPE_SELECT = {
},
};
const LEAVE_WORKFLOW_SELECT = {
orderBy: { created_at: "desc" },
take: 1,
select: {
id: true,
current_status: true,
current_step_id: true,
workflow_tasks: {
where: { status: "pending" },
orderBy: { created_at: "asc" },
take: 1,
select: {
id: true,
step_id: true,
step_name: true,
assignee_id: true,
assignee_role: true,
},
},
workflow_history: {
orderBy: { created_at: "desc" },
take: 8,
select: {
id: true,
task_id: true,
actor_id: true,
action: true,
comment: true,
created_at: true,
actor: {
select: {
employee_no: true,
name: true,
},
},
},
},
},
};
function buildValidationError(details, statusCode = 400) {
return new AppError({
code: "VALID_001",
@@ -347,7 +387,43 @@ function mapLeaveTypeSummary(leaveType) {
};
}
function mapWorkflowHistoryItem(item) {
return {
id: item.id,
taskId: item.task_id ?? null,
actorId: item.actor_id,
actorName: item.actor?.name ?? null,
actorEmployeeNo: item.actor?.employee_no ?? null,
action: item.action,
comment: item.comment ?? null,
createdAt: item.created_at?.toISOString?.() ?? null,
};
}
function mapPendingWorkflow(instance) {
if (!instance || instance.current_status !== "pending") {
return null;
}
const task = instance.workflow_tasks?.[0] ?? null;
return {
instanceId: instance.id,
currentStatus: instance.current_status,
currentStepId: instance.current_step_id,
task: task
? {
id: task.id,
stepId: task.step_id,
stepName: task.step_name,
assigneeId: task.assignee_id,
assigneeRole: task.assignee_role,
}
: null,
};
}
function mapLeaveRequestResponse(leave) {
const latestWorkflow = leave.workflow_instances?.[0] ?? null;
return {
id: leave.id,
ownerId: leave.owner_id,
@@ -374,6 +450,8 @@ function mapLeaveRequestResponse(leave) {
name: leave.owner.name,
}
: null,
pendingWorkflow: mapPendingWorkflow(latestWorkflow),
approvalHistory: (latestWorkflow?.workflow_history ?? []).map(mapWorkflowHistoryItem),
createdAt: leave.created_at?.toISOString?.() ?? null,
updatedAt: leave.updated_at?.toISOString?.() ?? null,
};
@@ -562,6 +640,7 @@ async function leaveRoutes(fastify) {
name: true,
},
},
workflow_instances: LEAVE_WORKFLOW_SELECT,
},
}),
fastify.prisma.leaveRequest.count({ where }),
@@ -668,6 +747,7 @@ async function leaveRoutes(fastify) {
name: true,
},
},
workflow_instances: LEAVE_WORKFLOW_SELECT,
},
});
@@ -849,6 +929,7 @@ async function leaveRoutes(fastify) {
name: true,
},
},
workflow_instances: LEAVE_WORKFLOW_SELECT,
},
});
+43 -14
查看文件
@@ -225,10 +225,6 @@ const PURCHASE_DETAIL_SELECT = {
},
},
workflow_instances: {
where: {
entity_type: "purchase_request",
current_status: "pending",
},
orderBy: { created_at: "desc" },
take: 1,
select: {
@@ -247,6 +243,24 @@ const PURCHASE_DETAIL_SELECT = {
assignee_role: true,
},
},
workflow_history: {
orderBy: { created_at: "desc" },
take: 8,
select: {
id: true,
task_id: true,
actor_id: true,
action: true,
comment: true,
created_at: true,
actor: {
select: {
employee_no: true,
name: true,
},
},
},
},
},
},
};
@@ -537,20 +551,34 @@ function mapPurchaseOrderArchive(item) {
};
}
function mapWorkflowHistoryItem(item) {
return {
id: item.id,
taskId: item.task_id ?? null,
actorId: item.actor_id,
actorName: item.actor?.name ?? null,
actorEmployeeNo: item.actor?.employee_no ?? null,
action: item.action,
comment: item.comment ?? null,
createdAt: toIsoDateTime(item.created_at),
};
}
function mapPurchaseRequestDetail(item, request) {
const summary = mapPurchaseRequestSummary(item);
const pendingWorkflow = item.workflow_instances?.[0]
const latestWorkflow = item.workflow_instances?.[0] ?? null;
const pendingWorkflow = latestWorkflow?.current_status === "pending"
? {
instanceId: item.workflow_instances[0].id,
currentStatus: item.workflow_instances[0].current_status,
currentStepId: item.workflow_instances[0].current_step_id,
task: item.workflow_instances[0].workflow_tasks?.[0]
instanceId: latestWorkflow.id,
currentStatus: latestWorkflow.current_status,
currentStepId: latestWorkflow.current_step_id,
task: latestWorkflow.workflow_tasks?.[0]
? {
id: item.workflow_instances[0].workflow_tasks[0].id,
stepId: item.workflow_instances[0].workflow_tasks[0].step_id,
stepName: item.workflow_instances[0].workflow_tasks[0].step_name,
assigneeId: item.workflow_instances[0].workflow_tasks[0].assignee_id,
assigneeRole: item.workflow_instances[0].workflow_tasks[0].assignee_role,
id: latestWorkflow.workflow_tasks[0].id,
stepId: latestWorkflow.workflow_tasks[0].step_id,
stepName: latestWorkflow.workflow_tasks[0].step_name,
assigneeId: latestWorkflow.workflow_tasks[0].assignee_id,
assigneeRole: latestWorkflow.workflow_tasks[0].assignee_role,
}
: null,
}
@@ -580,6 +608,7 @@ function mapPurchaseRequestDetail(item, request) {
})),
archiveOrder: mapPurchaseOrderArchive(item.order_archive),
pendingWorkflow,
approvalHistory: (latestWorkflow?.workflow_history ?? []).map(mapWorkflowHistoryItem),
permissions: {
canEditDraft: item.status === "draft" && item.applicant_id === request.employee.id,
canSubmit: item.status === "draft" && item.applicant_id === request.employee.id && request.employee.permissionCodes.includes("procurement.submit"),