125 lines
3.7 KiB
TypeScript
125 lines
3.7 KiB
TypeScript
import { CheckCircle2, Copy } from 'lucide-react';
|
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
import { copyTextToClipboard } from '../../services/clipboard';
|
|
import { UnifiedModal } from '../common/UnifiedModal';
|
|
|
|
export type PlatformTaskCompletionDialogPayload = {
|
|
source: string;
|
|
message: string;
|
|
};
|
|
|
|
type PlatformTaskCompletionDialogProps = {
|
|
completion: PlatformTaskCompletionDialogPayload | null;
|
|
onClose: () => void;
|
|
overlayClassName?: string;
|
|
panelClassName?: string;
|
|
};
|
|
|
|
function buildPlatformTaskCompletionReport(
|
|
completion: PlatformTaskCompletionDialogPayload,
|
|
) {
|
|
return [`来源:${completion.source}`, `状态:${completion.message}`].join(
|
|
'\n',
|
|
);
|
|
}
|
|
|
|
export function PlatformTaskCompletionDialog({
|
|
completion,
|
|
onClose,
|
|
overlayClassName = 'platform-theme platform-theme--light !items-center',
|
|
panelClassName = 'platform-remap-surface rounded-[1.5rem]',
|
|
}: PlatformTaskCompletionDialogProps) {
|
|
const [copyState, setCopyState] = useState<'idle' | 'copied' | 'failed'>(
|
|
'idle',
|
|
);
|
|
const resetTimerRef = useRef<number | null>(null);
|
|
const reportText = useMemo(
|
|
() => (completion ? buildPlatformTaskCompletionReport(completion) : ''),
|
|
[completion],
|
|
);
|
|
|
|
useEffect(
|
|
() => () => {
|
|
if (resetTimerRef.current !== null) {
|
|
window.clearTimeout(resetTimerRef.current);
|
|
}
|
|
},
|
|
[],
|
|
);
|
|
|
|
useEffect(() => {
|
|
setCopyState('idle');
|
|
}, [completion?.source, completion?.message]);
|
|
|
|
const copyCompletion = () => {
|
|
if (!reportText) {
|
|
return;
|
|
}
|
|
|
|
void copyTextToClipboard(reportText).then((copied) => {
|
|
setCopyState(copied ? 'copied' : 'failed');
|
|
if (resetTimerRef.current !== null) {
|
|
window.clearTimeout(resetTimerRef.current);
|
|
}
|
|
resetTimerRef.current = window.setTimeout(() => {
|
|
resetTimerRef.current = null;
|
|
setCopyState('idle');
|
|
}, 1400);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<UnifiedModal
|
|
open={Boolean(completion)}
|
|
title="生成完成"
|
|
onClose={onClose}
|
|
size="sm"
|
|
overlayClassName={overlayClassName}
|
|
panelClassName={panelClassName}
|
|
bodyClassName="space-y-3 px-4 py-4 sm:px-5 sm:py-5"
|
|
footerClassName="justify-end px-4 py-4 sm:px-5"
|
|
footer={
|
|
<button
|
|
type="button"
|
|
onClick={copyCompletion}
|
|
disabled={!reportText}
|
|
className="platform-button platform-button--primary w-full justify-center gap-2 sm:w-auto"
|
|
>
|
|
{copyState === 'copied' ? (
|
|
<CheckCircle2 className="h-4 w-4" />
|
|
) : (
|
|
<Copy className="h-4 w-4" />
|
|
)}
|
|
{copyState === 'copied'
|
|
? '已复制'
|
|
: copyState === 'failed'
|
|
? '复制失败'
|
|
: '复制内容'}
|
|
</button>
|
|
}
|
|
>
|
|
{completion ? (
|
|
<>
|
|
<div className="rounded-[1rem] border border-[var(--platform-subpanel-border)] bg-white/72 px-3 py-2">
|
|
<div className="text-xs font-bold text-[var(--platform-text-soft)]">
|
|
来源
|
|
</div>
|
|
<div className="mt-1 break-words text-sm font-semibold leading-5 text-[var(--platform-text-strong)]">
|
|
{completion.source}
|
|
</div>
|
|
</div>
|
|
<div className="rounded-[1rem] border border-[var(--platform-subpanel-border)] bg-white/72 px-3 py-2">
|
|
<div className="text-xs font-bold text-[var(--platform-text-soft)]">
|
|
状态
|
|
</div>
|
|
<div className="mt-1 whitespace-pre-wrap break-words text-sm leading-6 text-[var(--platform-text-strong)]">
|
|
{completion.message}
|
|
</div>
|
|
</div>
|
|
</>
|
|
) : null}
|
|
</UnifiedModal>
|
|
);
|
|
}
|