LP6 完善请假采购体验与审批说明
这个提交包含在:
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
在新工单中引用
屏蔽一个用户