统一详情页操作区模板(05-31-unify-business-detail-ant-design)
这个提交包含在:
@@ -19,7 +19,12 @@ import { buildMobileApprovalsPath, shouldPreferMobileApprovalExperience } from "
|
||||
import { CardSkeleton } from "../components/common/CardSkeleton";
|
||||
import { ConfirmDialog } from "../components/common/ConfirmDialog";
|
||||
import { StatusBadge } from "../components/common/StatusBadge";
|
||||
import { DetailSideMeta } from "../components/patterns/DetailSideMeta";
|
||||
import {
|
||||
BusinessDetailActionPanel,
|
||||
BusinessDetailAside,
|
||||
BusinessDetailMain,
|
||||
BusinessDetailWorkspace,
|
||||
} from "../components/patterns/BusinessDetailTemplate";
|
||||
import { EntityOverviewHero } from "../components/patterns/EntityOverviewHero";
|
||||
import { StatStrip } from "../components/patterns/ListWorkspace";
|
||||
import { MetricCard } from "../components/patterns/MetricCard";
|
||||
@@ -298,8 +303,8 @@ export function WorkflowTaskDetailPage() {
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="detail-workspace-grid">
|
||||
<div className="space-y-5">
|
||||
<BusinessDetailWorkspace>
|
||||
<BusinessDetailMain>
|
||||
<SectionPanel title="当前状态与审批对象">
|
||||
<div className="space-y-4" data-testid="workflow-task-overview">
|
||||
<StatStrip columns={4} className="ops-status-strip">
|
||||
@@ -438,21 +443,14 @@ export function WorkflowTaskDetailPage() {
|
||||
)}
|
||||
</div>
|
||||
</SectionPanel>
|
||||
</div>
|
||||
</BusinessDetailMain>
|
||||
|
||||
<div className="space-y-5">
|
||||
<SectionPanel title="处理" className="workflow-action-panel">
|
||||
<div className="detail-action-stack">
|
||||
{actionError ? (
|
||||
<p
|
||||
className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600"
|
||||
data-testid="workflow-task-action-error"
|
||||
>
|
||||
{actionError}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
<div className="workflow-action-bar">
|
||||
<BusinessDetailAside>
|
||||
<BusinessDetailActionPanel
|
||||
title="处理"
|
||||
className="workflow-action-panel xl:top-20"
|
||||
secondaryActions={(
|
||||
<>
|
||||
<Button
|
||||
data-testid="workflow-task-approve"
|
||||
disabled={!allowedActions.has("approve") || mutation.isPending}
|
||||
@@ -491,101 +489,112 @@ export function WorkflowTaskDetailPage() {
|
||||
</button>
|
||||
</details>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
summary={(
|
||||
<>
|
||||
<div>节点:{detail.task.stepName}</div>
|
||||
<div>实例状态:{workflowInstanceStatusLabel(detail.workflowInstance?.currentStatus)}</div>
|
||||
<div>当前审批角色:{detail.task.assigneeRole ?? "-"}</div>
|
||||
<div>创建时间:{formatDateTime(detail.task.createdAt)}</div>
|
||||
<div>完成时间:{formatDateTime(detail.task.completedAt)}</div>
|
||||
<div>发起时间:{formatDateTime(detail.workflowInstance?.startedAt)}</div>
|
||||
</>
|
||||
)}
|
||||
testId="workflow-task-action-panel"
|
||||
>
|
||||
{actionError ? (
|
||||
<p
|
||||
className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600"
|
||||
data-testid="workflow-task-action-error"
|
||||
>
|
||||
{actionError}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
{activeSecondaryAction === "reject" ? (
|
||||
<div className="detail-action-card space-y-2">
|
||||
<p className="text-sm font-medium text-zinc-800">驳回意见</p>
|
||||
<Textarea
|
||||
data-testid="workflow-task-reject-comment"
|
||||
onChange={(event) => setRejectComment(event.target.value)}
|
||||
rows={3}
|
||||
value={rejectComment}
|
||||
/>
|
||||
<Button
|
||||
data-testid="workflow-task-reject"
|
||||
variant="secondary"
|
||||
disabled={!allowedActions.has("reject") || mutation.isPending || rejectComment.trim().length < 1}
|
||||
onClick={() => requestWorkflowAction("reject")}
|
||||
type="button"
|
||||
>
|
||||
确认驳回
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{activeSecondaryAction === "reject" ? (
|
||||
<div className="detail-action-card space-y-2">
|
||||
<p className="text-sm font-medium text-zinc-800">驳回意见</p>
|
||||
<Textarea
|
||||
data-testid="workflow-task-reject-comment"
|
||||
onChange={(event) => setRejectComment(event.target.value)}
|
||||
rows={3}
|
||||
value={rejectComment}
|
||||
/>
|
||||
<Button
|
||||
data-testid="workflow-task-reject"
|
||||
variant="secondary"
|
||||
disabled={!allowedActions.has("reject") || mutation.isPending || rejectComment.trim().length < 1}
|
||||
onClick={() => requestWorkflowAction("reject")}
|
||||
type="button"
|
||||
>
|
||||
确认驳回
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
{activeSecondaryAction === "return" ? (
|
||||
<div className="detail-action-card space-y-2">
|
||||
<p className="text-sm font-medium text-zinc-800">退回意见</p>
|
||||
<Textarea
|
||||
data-testid="workflow-task-return-comment"
|
||||
onChange={(event) => setReturnComment(event.target.value)}
|
||||
rows={3}
|
||||
value={returnComment}
|
||||
/>
|
||||
<Button
|
||||
data-testid="workflow-task-return"
|
||||
variant="secondary"
|
||||
disabled={!allowedActions.has("return") || mutation.isPending || returnComment.trim().length < 1}
|
||||
onClick={() => requestWorkflowAction("return")}
|
||||
type="button"
|
||||
>
|
||||
确认退回
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{activeSecondaryAction === "return" ? (
|
||||
<div className="detail-action-card space-y-2">
|
||||
<p className="text-sm font-medium text-zinc-800">退回意见</p>
|
||||
<Textarea
|
||||
data-testid="workflow-task-return-comment"
|
||||
onChange={(event) => setReturnComment(event.target.value)}
|
||||
rows={3}
|
||||
value={returnComment}
|
||||
/>
|
||||
<Button
|
||||
data-testid="workflow-task-return"
|
||||
variant="secondary"
|
||||
disabled={!allowedActions.has("return") || mutation.isPending || returnComment.trim().length < 1}
|
||||
onClick={() => requestWorkflowAction("return")}
|
||||
type="button"
|
||||
>
|
||||
确认退回
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{activeSecondaryAction === "transfer" && canTransfer ? (
|
||||
<div className="detail-action-card space-y-2">
|
||||
<p className="text-sm font-medium text-zinc-800">转审</p>
|
||||
<select
|
||||
className="select-std"
|
||||
data-testid="workflow-task-transfer-approver"
|
||||
onChange={(event) => setSelectedApprover(event.target.value)}
|
||||
value={selectedApprover}
|
||||
>
|
||||
<option value="">请选择目标审批人</option>
|
||||
{(approverQuery.data?.items ?? []).map((item) => (
|
||||
<option key={item.id} value={item.id}>
|
||||
{item.name} ({item.employeeNo})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<Textarea
|
||||
data-testid="workflow-task-transfer-reason"
|
||||
onChange={(event) => setTransferReason(event.target.value)}
|
||||
rows={3}
|
||||
value={transferReason}
|
||||
/>
|
||||
<Button
|
||||
data-testid="workflow-task-transfer"
|
||||
variant="secondary"
|
||||
disabled={
|
||||
!allowedActions.has("transfer") ||
|
||||
mutation.isPending ||
|
||||
!selectedApprover ||
|
||||
transferReason.trim().length < 10
|
||||
}
|
||||
onClick={requestWorkflowTransfer}
|
||||
type="button"
|
||||
>
|
||||
确认转审
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</SectionPanel>
|
||||
|
||||
<DetailSideMeta title="任务摘要">
|
||||
<div>节点:{detail.task.stepName}</div>
|
||||
<div>实例状态:{workflowInstanceStatusLabel(detail.workflowInstance?.currentStatus)}</div>
|
||||
<div>当前审批角色:{detail.task.assigneeRole ?? "-"}</div>
|
||||
<div>创建时间:{formatDateTime(detail.task.createdAt)}</div>
|
||||
<div>完成时间:{formatDateTime(detail.task.completedAt)}</div>
|
||||
<div>发起时间:{formatDateTime(detail.workflowInstance?.startedAt)}</div>
|
||||
</DetailSideMeta>
|
||||
</div>
|
||||
</div>
|
||||
{activeSecondaryAction === "transfer" && canTransfer ? (
|
||||
<div className="detail-action-card space-y-2">
|
||||
<p className="text-sm font-medium text-zinc-800">转审</p>
|
||||
<select
|
||||
className="select-std"
|
||||
data-testid="workflow-task-transfer-approver"
|
||||
onChange={(event) => setSelectedApprover(event.target.value)}
|
||||
value={selectedApprover}
|
||||
>
|
||||
<option value="">请选择目标审批人</option>
|
||||
{(approverQuery.data?.items ?? []).map((item) => (
|
||||
<option key={item.id} value={item.id}>
|
||||
{item.name} ({item.employeeNo})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<Textarea
|
||||
data-testid="workflow-task-transfer-reason"
|
||||
onChange={(event) => setTransferReason(event.target.value)}
|
||||
rows={3}
|
||||
value={transferReason}
|
||||
/>
|
||||
<Button
|
||||
data-testid="workflow-task-transfer"
|
||||
variant="secondary"
|
||||
disabled={
|
||||
!allowedActions.has("transfer") ||
|
||||
mutation.isPending ||
|
||||
!selectedApprover ||
|
||||
transferReason.trim().length < 10
|
||||
}
|
||||
onClick={requestWorkflowTransfer}
|
||||
type="button"
|
||||
>
|
||||
确认转审
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</BusinessDetailActionPanel>
|
||||
</BusinessDetailAside>
|
||||
</BusinessDetailWorkspace>
|
||||
</PageScaffold>
|
||||
<ConfirmDialog
|
||||
open={Boolean(confirmCopy)}
|
||||
|
||||
在新工单中引用
屏蔽一个用户