feat(detail-page-structure-progress-actions): 统一详情处理进度与操作区
这个提交包含在:
@@ -98,7 +98,7 @@ export function BusinessDetailActionPanel({
|
||||
const hasContentBeforeSummary = Boolean(primaryAction || secondaryActions || moreActions || hasChildren);
|
||||
|
||||
return (
|
||||
<SectionPanel title={title} actions={status} className={cn("detail-action-panel xl:sticky xl:top-24", className)}>
|
||||
<SectionPanel title={title} actions={status} className={cn("detail-action-panel lg:sticky lg:top-24", className)}>
|
||||
<div className="detail-action-stack" data-testid={testId}>
|
||||
{primaryAction ? <div className="grid gap-2">{primaryAction}</div> : null}
|
||||
{secondaryActions ? <div className="workflow-action-bar">{secondaryActions}</div> : null}
|
||||
|
||||
+20
-11
@@ -1,12 +1,15 @@
|
||||
import { AlertCircle, Check, Circle, Clock, ExternalLink } from "lucide-react";
|
||||
import { AlertCircle, Ban, Check, Circle, Clock, ExternalLink } from "lucide-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import type { ReimbursementProcessingProgress as ProcessingProgress } from "../../api/reimbursements";
|
||||
import type { ProcessingProgress as ProcessingProgressValue } from "../../types/processingProgress";
|
||||
import { formatDisplayDateTime } from "../../lib/displayFormat";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
type Props = {
|
||||
progress: ProcessingProgress;
|
||||
progress: ProcessingProgressValue;
|
||||
ariaLabel: string;
|
||||
testId: string;
|
||||
mobile?: boolean;
|
||||
targetLinkLabel?: string;
|
||||
};
|
||||
|
||||
const STATE_TEXT = {
|
||||
@@ -14,15 +17,18 @@ const STATE_TEXT = {
|
||||
current: "处理中",
|
||||
pending: "待处理",
|
||||
exception: "需处理",
|
||||
terminated: "已终止",
|
||||
} as const;
|
||||
|
||||
export function ReimbursementProcessingProgress({ progress, mobile = false }: Props) {
|
||||
export function ProcessingProgress({
|
||||
progress,
|
||||
ariaLabel,
|
||||
testId,
|
||||
mobile = false,
|
||||
targetLinkLabel = "查看详情",
|
||||
}: Props) {
|
||||
return (
|
||||
<ol
|
||||
className="space-y-0"
|
||||
data-testid={mobile ? "mobile-reimbursement-processing-progress" : "reimbursement-workflow-progress"}
|
||||
aria-label="报销处理进度"
|
||||
>
|
||||
<ol className="space-y-0" data-testid={testId} aria-label={ariaLabel}>
|
||||
{progress.stages.map((stage, index) => {
|
||||
const expanded = stage.state === "current" || stage.state === "exception" || Boolean(stage.comment);
|
||||
const Icon = stage.state === "completed"
|
||||
@@ -31,7 +37,9 @@ export function ReimbursementProcessingProgress({ progress, mobile = false }: Pr
|
||||
? Clock
|
||||
: stage.state === "exception"
|
||||
? AlertCircle
|
||||
: Circle;
|
||||
: stage.state === "terminated"
|
||||
? Ban
|
||||
: Circle;
|
||||
const facts = [stage.actorName, stage.occurredAt ? formatDisplayDateTime(stage.occurredAt) : null, stage.result]
|
||||
.filter(Boolean);
|
||||
|
||||
@@ -47,6 +55,7 @@ export function ReimbursementProcessingProgress({ progress, mobile = false }: Pr
|
||||
stage.state === "current" && "border-blue-300 bg-blue-50 text-blue-700",
|
||||
stage.state === "exception" && "border-red-300 bg-red-50 text-red-700",
|
||||
stage.state === "pending" && "border-zinc-300 text-zinc-400",
|
||||
stage.state === "terminated" && "border-zinc-300 bg-zinc-100 text-zinc-500",
|
||||
)}
|
||||
aria-hidden="true"
|
||||
>
|
||||
@@ -69,7 +78,7 @@ export function ReimbursementProcessingProgress({ progress, mobile = false }: Pr
|
||||
className="mt-2 inline-flex min-h-11 items-center gap-1 text-sm font-medium text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2"
|
||||
to={stage.targetHref}
|
||||
>
|
||||
查看所在付款批次
|
||||
{targetLinkLabel}
|
||||
<ExternalLink aria-hidden="true" className="size-4" />
|
||||
</Link>
|
||||
) : null}
|
||||
在新工单中引用
屏蔽一个用户