统一详情页操作区模板(05-31-unify-business-detail-ant-design)
这个提交包含在:
@@ -0,0 +1,117 @@
|
||||
import { Children, type ReactNode } from "react";
|
||||
import { cn } from "../../lib/utils";
|
||||
import { SectionPanel } from "./SectionPanel";
|
||||
|
||||
export function BusinessDetailWorkspace({
|
||||
children,
|
||||
className,
|
||||
testId,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
testId?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("detail-workspace-grid", className)} data-testid={testId}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function BusinessDetailMain({
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return <div className={cn("space-y-5", className)}>{children}</div>;
|
||||
}
|
||||
|
||||
export function BusinessDetailAside({
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return <div className={cn("space-y-5", className)}>{children}</div>;
|
||||
}
|
||||
|
||||
export function BusinessDetailFactGrid({
|
||||
children,
|
||||
className,
|
||||
testId,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
testId?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("detail-fact-grid", className)} data-testid={testId}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function BusinessDetailFact({
|
||||
label,
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
label: ReactNode;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("detail-fact-card", className)}>
|
||||
<div className="detail-fact-card__label">{label}</div>
|
||||
<div className="detail-fact-card__value">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function BusinessDetailActionPanel({
|
||||
title = "操作",
|
||||
status,
|
||||
primaryAction,
|
||||
secondaryActions,
|
||||
moreActions,
|
||||
summary,
|
||||
children,
|
||||
className,
|
||||
testId,
|
||||
}: {
|
||||
title?: string;
|
||||
status?: ReactNode;
|
||||
primaryAction?: ReactNode;
|
||||
secondaryActions?: ReactNode;
|
||||
moreActions?: ReactNode;
|
||||
summary?: ReactNode;
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
testId?: string;
|
||||
}) {
|
||||
const visibleChildren = Children.toArray(children);
|
||||
const hasActionContent = Boolean(primaryAction || secondaryActions || moreActions);
|
||||
const hasChildren = visibleChildren.length > 0;
|
||||
const hasContentBeforeSummary = Boolean(primaryAction || secondaryActions || moreActions || hasChildren);
|
||||
|
||||
return (
|
||||
<SectionPanel title={title} actions={status} className={cn("detail-action-panel xl:sticky xl: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}
|
||||
{moreActions ? <div className="border-t border-zinc-200 pt-3">{moreActions}</div> : null}
|
||||
{hasChildren ? (
|
||||
<div className={cn(hasActionContent && "border-t border-zinc-200 pt-3")}>{children}</div>
|
||||
) : null}
|
||||
{summary ? (
|
||||
<div className={cn(hasContentBeforeSummary && "border-t border-zinc-200 pt-3")}>
|
||||
<div className="space-y-2 text-sm text-zinc-600">{summary}</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</SectionPanel>
|
||||
);
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户