A2 收口统一审批中心入口与状态
这个提交包含在:
@@ -53,8 +53,8 @@ function workflowStatusLabel(status: string | undefined) {
|
||||
}
|
||||
|
||||
const labels: Record<string, string> = {
|
||||
pending: "待派发",
|
||||
completed: "已完成",
|
||||
pending: "待处理",
|
||||
completed: "已处理",
|
||||
rejected: "已驳回",
|
||||
cancelled: "已取消",
|
||||
skipped: "已跳过",
|
||||
@@ -63,6 +63,46 @@ function workflowStatusLabel(status: string | undefined) {
|
||||
return labels[status] ?? status;
|
||||
}
|
||||
|
||||
function workflowInstanceStatusLabel(status: string | undefined | null) {
|
||||
if (!status) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const labels: Record<string, string> = {
|
||||
active: "审批中",
|
||||
approved: "已通过",
|
||||
rejected: "已驳回",
|
||||
terminated: "已终止",
|
||||
cancelled: "已取消",
|
||||
completed: "已完成",
|
||||
};
|
||||
|
||||
return labels[status] ?? status;
|
||||
}
|
||||
|
||||
function workflowActionLabel(action: string | undefined | null) {
|
||||
if (!action) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const labels: Record<string, string> = {
|
||||
submit: "提交",
|
||||
approve: "通过",
|
||||
reject: "驳回",
|
||||
return: "退回",
|
||||
transfer: "转审",
|
||||
withdraw: "撤回",
|
||||
cancel: "取消",
|
||||
skip: "跳过",
|
||||
};
|
||||
|
||||
return labels[action] ?? action;
|
||||
}
|
||||
|
||||
function isAlreadyProcessedTaskError(error: unknown) {
|
||||
return isApiError(error) && error.details?.task === "already_processed";
|
||||
}
|
||||
|
||||
export function WorkflowTaskDetailPage() {
|
||||
const { taskId = "" } = useParams();
|
||||
const navigate = useNavigate();
|
||||
@@ -125,6 +165,12 @@ export function WorkflowTaskDetailPage() {
|
||||
toast.success(messages[action] ?? "操作成功");
|
||||
},
|
||||
onError: (error) => {
|
||||
if (isAlreadyProcessedTaskError(error)) {
|
||||
void Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: ["workflow", "tasks"] }),
|
||||
queryClient.invalidateQueries({ queryKey: ["workflow", "task", taskId] }),
|
||||
]);
|
||||
}
|
||||
let msg: string;
|
||||
if (error instanceof Error && !isApiError(error)) {
|
||||
msg = error.message;
|
||||
@@ -178,8 +224,8 @@ export function WorkflowTaskDetailPage() {
|
||||
}
|
||||
|
||||
const detail = detailQuery.data;
|
||||
const isLeaveTask = detail.workflowInstance?.entityType === "leave";
|
||||
const canTransfer = allowedActions.has("transfer");
|
||||
const allowedActionLabels = detail.allowedActions.map(workflowActionLabel).join(" / ");
|
||||
|
||||
return (
|
||||
<PageScaffold>
|
||||
@@ -220,7 +266,7 @@ export function WorkflowTaskDetailPage() {
|
||||
</div>
|
||||
<div className="rounded-lg border border-zinc-200 px-4 py-3 text-sm">
|
||||
<div className="text-zinc-500">可执行动作</div>
|
||||
<div className="mt-2 font-medium text-zinc-900">{detail.allowedActions.length ? detail.allowedActions.join(" / ") : "-"}</div>
|
||||
<div className="mt-2 font-medium text-zinc-900">{allowedActionLabels || "-"}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -374,7 +420,7 @@ export function WorkflowTaskDetailPage() {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{canTransfer && !isLeaveTask ? (
|
||||
{canTransfer ? (
|
||||
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
|
||||
<p className="text-sm font-medium text-zinc-800">转审</p>
|
||||
<select
|
||||
@@ -421,7 +467,7 @@ export function WorkflowTaskDetailPage() {
|
||||
detail.history.map((item) => (
|
||||
<div className="rounded-lg border border-zinc-200 px-3 py-2 text-sm" key={item.id}>
|
||||
<div className="font-medium text-zinc-900">
|
||||
{item.action} · {item.actorName || item.actorId}
|
||||
{workflowActionLabel(item.action)} · {item.actorName || item.actorId}
|
||||
</div>
|
||||
<div className="text-zinc-600">{item.comment || "-"}</div>
|
||||
<div className="text-xs text-zinc-500">{item.createdAt || "-"}</div>
|
||||
@@ -437,7 +483,7 @@ export function WorkflowTaskDetailPage() {
|
||||
<div className="space-y-6">
|
||||
<DetailSideMeta title="任务摘要">
|
||||
<div>节点:{detail.task.stepName}</div>
|
||||
<div>实例状态:{detail.workflowInstance?.currentStatus ?? "-"}</div>
|
||||
<div>实例状态:{workflowInstanceStatusLabel(detail.workflowInstance?.currentStatus)}</div>
|
||||
<div>当前审批角色:{detail.task.assigneeRole ?? "-"}</div>
|
||||
<div>创建时间:{formatDateTime(detail.task.createdAt)}</div>
|
||||
<div>完成时间:{formatDateTime(detail.task.completedAt)}</div>
|
||||
|
||||
在新工单中引用
屏蔽一个用户