refactor: unlock dev flow, dedupe EcommercePage, extract shell UI components
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import { DeleteOutlined, MenuFoldOutlined, MenuUnfoldOutlined, ReloadOutlined } from "@ant-design/icons";
|
||||
import type { MouseEvent as ReactMouseEvent } from "react";
|
||||
import type { EcommerceHistoryRecord } from "../utils/clonePersistence";
|
||||
|
||||
// 页面内的 EcommerceHistoryRecord 比 clonePersistence 版本更丰富(多了 status/errorMessage/turns),
|
||||
// 这里用 intersection 补齐侧栏实际用到的字段,避免依赖页面的内部类型。
|
||||
type HistoryRecord = EcommerceHistoryRecord & {
|
||||
status?: "generating" | "done" | "failed";
|
||||
};
|
||||
|
||||
interface CommandHistorySidebarProps {
|
||||
collapsed: boolean;
|
||||
showBackdrop: boolean;
|
||||
records: HistoryRecord[];
|
||||
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: HistoryRecord) => 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user