feat(client): 完成 P3 业务页联动闭环(D6/D8/D10/D11)
- 待办:列表/详情 + approve/reject/return/transfer(D6) - 报销:列表/详情 + create/submit/withdraw/pay(D8) - 票据:列表/上传/OCR轮询/绑定/预览(D10) - 统一:Api types + 错误映射 + react-query缓存失效(D11)
这个提交包含在:
@@ -0,0 +1,163 @@
|
||||
import { apiRequestData } from "./http";
|
||||
|
||||
export type WorkflowTaskSummary = {
|
||||
id: string;
|
||||
instanceId: string;
|
||||
stepId: string;
|
||||
stepName: string;
|
||||
assigneeId: string | null;
|
||||
assigneeRole: string | null;
|
||||
status: "pending" | "completed" | "rejected" | "cancelled" | "skipped";
|
||||
outcome: string | null;
|
||||
createdAt: string;
|
||||
completedAt: string | null;
|
||||
workflowInstance: {
|
||||
entityType: string;
|
||||
entityId: string;
|
||||
currentStatus: string;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type WorkflowTaskListResponse = {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
items: WorkflowTaskSummary[];
|
||||
};
|
||||
|
||||
export type WorkflowHistoryItem = {
|
||||
id: string;
|
||||
taskId: string | null;
|
||||
actorId: string;
|
||||
actorName: string;
|
||||
actorEmployeeNo: string;
|
||||
action: string;
|
||||
comment: string | null;
|
||||
payload: Record<string, unknown> | null;
|
||||
createdAt: string | null;
|
||||
};
|
||||
|
||||
export type WorkflowTaskDetail = {
|
||||
task: {
|
||||
id: string;
|
||||
instanceId: string;
|
||||
stepId: string;
|
||||
stepName: string;
|
||||
assigneeId: string | null;
|
||||
assigneeRole: string | null;
|
||||
status: string;
|
||||
outcome: string | null;
|
||||
comment: string | null;
|
||||
createdAt: string | null;
|
||||
completedAt: string | null;
|
||||
};
|
||||
workflowInstance: {
|
||||
id: string;
|
||||
currentStatus: string;
|
||||
currentStepId: string;
|
||||
startedAt: string | null;
|
||||
completedAt: string | null;
|
||||
} | null;
|
||||
reimbursement: {
|
||||
id: string;
|
||||
formNumber: string | null;
|
||||
status: string;
|
||||
reimbursementDate: string | null;
|
||||
totalAmount: string | null;
|
||||
description: string | null;
|
||||
owner: {
|
||||
id: string;
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
} | null;
|
||||
submitter: {
|
||||
id: string;
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
} | null;
|
||||
} | null;
|
||||
allowedActions: Array<"approve" | "reject" | "return" | "transfer">;
|
||||
history: WorkflowHistoryItem[];
|
||||
};
|
||||
|
||||
export type WorkflowApprover = {
|
||||
id: string;
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
email: string;
|
||||
roleCodes: string[];
|
||||
};
|
||||
|
||||
export type WorkflowApproverListResponse = {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
items: WorkflowApprover[];
|
||||
};
|
||||
|
||||
export type WorkflowTaskListQuery = {
|
||||
status?: "pending" | "completed" | "rejected" | "cancelled" | "skipped";
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
};
|
||||
|
||||
export type WorkflowApproverQuery = {
|
||||
keyword?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
};
|
||||
|
||||
function toQueryString(query: Record<string, string | number | undefined>) {
|
||||
const params = new URLSearchParams();
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value == null || value === "") {
|
||||
continue;
|
||||
}
|
||||
params.set(key, String(value));
|
||||
}
|
||||
|
||||
const encoded = params.toString();
|
||||
return encoded ? `?${encoded}` : "";
|
||||
}
|
||||
|
||||
export async function fetchWorkflowTasks(query: WorkflowTaskListQuery) {
|
||||
return apiRequestData<WorkflowTaskListResponse>(`/api/workflow/tasks${toQueryString(query)}`);
|
||||
}
|
||||
|
||||
export async function fetchWorkflowTaskDetail(taskId: string) {
|
||||
return apiRequestData<WorkflowTaskDetail>(`/api/workflow/tasks/${taskId}`);
|
||||
}
|
||||
|
||||
export async function fetchWorkflowApprovers(query: WorkflowApproverQuery = {}) {
|
||||
return apiRequestData<WorkflowApproverListResponse>(
|
||||
`/api/workflow/approvers${toQueryString(query as Record<string, string | number | undefined>)}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function approveWorkflowTask(taskId: string) {
|
||||
return apiRequestData<Record<string, unknown>>(`/api/workflow/tasks/${taskId}/approve`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function rejectWorkflowTask(taskId: string, comment: string) {
|
||||
return apiRequestData<Record<string, unknown>>(`/api/workflow/tasks/${taskId}/reject`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ comment }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function returnWorkflowTask(taskId: string, comment: string) {
|
||||
return apiRequestData<Record<string, unknown>>(`/api/workflow/tasks/${taskId}/return`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ comment }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function transferWorkflowTask(taskId: string, toApproverId: string, reason: string) {
|
||||
return apiRequestData<Record<string, unknown>>(`/api/workflow/tasks/${taskId}/transfer`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ toApproverId, reason }),
|
||||
});
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户