117 lines
4.3 KiB
TypeScript
117 lines
4.3 KiB
TypeScript
import { DeleteOutlined, MenuFoldOutlined, MenuUnfoldOutlined, ReloadOutlined } from "@ant-design/icons";
|
|
import type { MouseEvent as ReactMouseEvent } from "react";
|
|
import type { EcommerceHistoryRecord } from "../utils/clonePersistence";
|
|
|
|
interface CommandHistorySidebarProps {
|
|
collapsed: boolean;
|
|
showBackdrop: boolean;
|
|
records: EcommerceHistoryRecord[];
|
|
activeRecordId: string | null;
|
|
isRefreshing: boolean;
|
|
refreshMessage: string | null;
|
|
refreshStamp: number;
|
|
refreshTick: number;
|
|
outputLabels: Array<{ key: string; label: string }>;
|
|
formatHistoryTime: (timestamp: number) => string;
|
|
onToggleCollapsed: () => void;
|
|
onCollapse: () => void;
|
|
onNewConversation: () => void;
|
|
onRefresh: () => void;
|
|
onOpenRecord: (record: EcommerceHistoryRecord) => void;
|
|
onDeleteRecord: (recordId: string, event: ReactMouseEvent) => void;
|
|
}
|
|
|
|
// 生成记录侧栏:折叠/展开、新建对话、刷新历史、记录列表(点击查看/删除)。
|
|
export default function CommandHistorySidebar({
|
|
collapsed,
|
|
showBackdrop,
|
|
records,
|
|
activeRecordId,
|
|
isRefreshing,
|
|
refreshMessage,
|
|
refreshStamp,
|
|
refreshTick,
|
|
outputLabels,
|
|
formatHistoryTime,
|
|
onToggleCollapsed,
|
|
onCollapse,
|
|
onNewConversation,
|
|
onRefresh,
|
|
onOpenRecord,
|
|
onDeleteRecord,
|
|
}: CommandHistorySidebarProps) {
|
|
return (
|
|
<>
|
|
{showBackdrop ? (
|
|
<div className="ecom-command-history__backdrop" role="presentation" onClick={onCollapse} />
|
|
) : null}
|
|
|
|
<aside className="ecom-command-history" aria-label="生成历史">
|
|
<div className="ecom-command-history__tools">
|
|
<button
|
|
type="button"
|
|
className="ecom-command-history__toggle"
|
|
onClick={onToggleCollapsed}
|
|
title={collapsed ? "展开记录" : "收起记录"}
|
|
aria-label={collapsed ? "展开记录" : "收起记录"}
|
|
aria-expanded={!collapsed}
|
|
>
|
|
{collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
</button>
|
|
<button type="button" className="ecom-command-history__new" onClick={onNewConversation}>
|
|
新对话
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className={`ecom-command-history__refresh${isRefreshing ? " is-refreshing" : ""}`}
|
|
aria-label={isRefreshing ? "刷新中" : "刷新历史"}
|
|
title={isRefreshing ? "刷新中" : "刷新历史"}
|
|
onPointerDown={onRefresh}
|
|
onClick={onRefresh}
|
|
disabled={isRefreshing}
|
|
>
|
|
<ReloadOutlined />
|
|
</button>
|
|
</div>
|
|
<div className="ecom-command-history__heading">
|
|
<strong>生成记录</strong>
|
|
<span>{records.length} 条</span>
|
|
</div>
|
|
{refreshMessage ? (
|
|
<p key={refreshStamp} className="ecom-command-history__refresh-note" role="status">
|
|
{refreshMessage}
|
|
</p>
|
|
) : null}
|
|
<nav className="ecom-command-history__list" aria-label="历史对话">
|
|
{records.length ? (
|
|
records.map((record) => {
|
|
const outputLabel = outputLabels.find((option) => option.key === record.output)?.label || "生成记录";
|
|
const statusLabel =
|
|
record.status === "generating" ? "生成中" : record.status === "failed" ? "失败" : formatHistoryTime(record.createdAt);
|
|
return (
|
|
<div key={`${record.id}-${refreshTick}`} className={`ecom-command-history__item${activeRecordId === record.id ? " is-active" : ""}`}>
|
|
<button type="button" className="ecom-command-history__item-main" onClick={() => onOpenRecord(record)}>
|
|
<strong>{record.title}</strong>
|
|
<span>{outputLabel} · {statusLabel}</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="ecom-command-history__item-delete"
|
|
aria-label="删除此记录"
|
|
title="删除"
|
|
onClick={(e) => onDeleteRecord(record.id, e)}
|
|
>
|
|
<DeleteOutlined />
|
|
</button>
|
|
</div>
|
|
);
|
|
})
|
|
) : (
|
|
<p className="ecom-command-history__empty">暂无生成记录</p>
|
|
)}
|
|
</nav>
|
|
</aside>
|
|
</>
|
|
);
|
|
}
|