import { useEffect, useState } from "react";
import { Table, Toast } from "@douyinfe/semi-ui-19";
import { api, formatNumber, formatTime, stateLabels } from "../api";
import { PnlChart } from "../components/PnlChart";
import type { Alpha, Pnl, Research } from "../types";
import type { ToolCardProps } from "./types";
export function AlphaToolCard({ call, onAction, timezone }: ToolCardProps) {
const result = call.result ?? {};
const items = Array.isArray(result.items) ? result.items : [];
const isSearch = call.name === "search_alphas";
const alphas = (
isSearch ? items : call.name === "get_alpha" && result.id ? [result] : []
) as Alpha[];
const openAlpha = (id: string) =>
onAction({ type: "open_alpha", alpha_id: id, nonce: Date.now() });
return (
<>
{call.preview.targets?.map((target) => (
{target.alpha_id} 的修改
{(["note", "tags", "favorite", "state"] as const)
.filter(
(key) =>
JSON.stringify(target.before[key]) !==
JSON.stringify(target.after[key]),
)
.map((key) => (
{
{
note: "备注",
tags: "标签",
favorite: "收藏",
state: "研究状态",
}[key]
}
修改前
{researchValue(key, target.before[key])}
修改后
{researchValue(key, target.after[key])}
))}
))}
{alphas.length > 0 && (
{alphas.map((alpha) => (
{alpha.id} · {alpha.region ?? "地区未提供"}
dataSource={[alpha]}
rowKey="id"
pagination={false}
size="small"
tableLayout="fixed"
columns={[
{
title: "Sharpe",
key: "sharpe",
render: (_, alpha) => formatNumber(alpha.sharpe),
},
{
title: "Fitness",
key: "fitness",
render: (_, alpha) => formatNumber(alpha.fitness),
},
{
title: "Turnover",
key: "turnover",
render: (_, alpha) =>
alpha.turnover == null
? "未提供"
: `${formatNumber(alpha.turnover * 100)}%`,
},
]}
/>
本地快照 · {formatTime(alpha.synced_at, timezone)}
))}
)}
{isSearch && (
共 {String(result.total ?? 0)} 条,当前返回 {items.length} 条。
{!!result.filters && (
)}
)}
{call.name === "get_alpha_facets" && call.status === "completed" && (
已同步 {String(result.total ?? 0)} 条 Alpha · 收藏{" "}
{String(result.favorites ?? 0)} 条
地区:
{Array.isArray(result.region) ? result.region.join("、") : "未提供"}
)}
{call.name === "get_alpha_pnl" && call.status === "completed" && (
)}
{result.ok === true && (
操作已保存。
{typeof result.alpha_id === "string" && (
)}
)}
{typeof result.updated === "number" && (
已更新 {result.updated} 条研究记录。
)}
>
);
}
function researchValue(key: keyof Research, value: unknown) {
if (key === "favorite") return value ? "已收藏" : "未收藏";
if (key === "state")
return (
stateLabels[String(value) as keyof typeof stateLabels] ?? String(value)
);
if (Array.isArray(value)) return value.join("、") || "无";
return String(value || "空");
}
function ChatPnl({
result,
timezone,
}: {
result: Record;
timezone?: string;
}) {
const [pnl, setPnl] = useState(null);
useEffect(() => {
let active = true;
if (result.cached && typeof result.alpha_id === "string")
api(`/alphas/${encodeURIComponent(result.alpha_id)}/pnl`)
.then((value) => {
if (active) setPnl(value);
})
.catch((error) => {
if (active) Toast.error(error.message);
});
return () => {
active = false;
};
}, [result.alpha_id, result.fetched_at, result.cached]);
return result.cached ? (
{pnl &&
}
{String(result.count)} 条记录 · 缓存于{" "}
{formatTime(result.fetched_at as string, timezone)}
) : (
尚无 PnL 缓存,可以请求创建 PnL 刷新任务。
);
}