feat: add AI research chatbot with confirmed business tools
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
} from "@douyinfe/semi-ui-19";
|
||||
import {
|
||||
api,
|
||||
ApiError,
|
||||
displayValue,
|
||||
formatTime,
|
||||
patch,
|
||||
@@ -39,6 +40,8 @@ export function AlphaDetail({
|
||||
onClose,
|
||||
onSaved,
|
||||
onTask,
|
||||
suspended = false,
|
||||
chatOffset = 0,
|
||||
}: {
|
||||
id: string | null;
|
||||
version: string;
|
||||
@@ -47,6 +50,8 @@ export function AlphaDetail({
|
||||
onClose: () => void;
|
||||
onSaved: () => void;
|
||||
onTask: () => void;
|
||||
suspended?: boolean;
|
||||
chatOffset?: number;
|
||||
}) {
|
||||
const [detail, setDetail] = useState<Detail | null>(null);
|
||||
const [pnl, setPnl] = useState<Pnl | null>(null);
|
||||
@@ -54,10 +59,12 @@ export function AlphaDetail({
|
||||
const [tagText, setTagText] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [conflict, setConflict] = useState(false);
|
||||
const [tab, setTab] = useState("overview");
|
||||
const dirty = useRef(false);
|
||||
useEffect(() => {
|
||||
dirty.current = false;
|
||||
setConflict(false);
|
||||
setDetail(null);
|
||||
setResearch(null);
|
||||
setPnl(null);
|
||||
@@ -75,6 +82,11 @@ export function AlphaDetail({
|
||||
if (!dirty.current) {
|
||||
setResearch(value.research);
|
||||
setTagText(value.research.tags.join(", "));
|
||||
} else if (
|
||||
research &&
|
||||
value.research.version !== research.version
|
||||
) {
|
||||
setConflict(true);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -120,10 +132,19 @@ export function AlphaDetail({
|
||||
.filter(Boolean),
|
||||
});
|
||||
dirty.current = false;
|
||||
setConflict(false);
|
||||
Toast.success("研究记录已保存");
|
||||
onSaved();
|
||||
} catch (e) {
|
||||
Toast.error((e as Error).message);
|
||||
if (e instanceof ApiError && e.status === 409) {
|
||||
setConflict(true);
|
||||
try {
|
||||
setDetail(await api<Detail>(`/alphas/${id}`));
|
||||
} catch {
|
||||
/* Preserve the draft if refresh fails. */
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
@@ -132,8 +153,10 @@ export function AlphaDetail({
|
||||
<SideSheet
|
||||
closeOnEsc={!taskPanelOpen}
|
||||
className="alpha-detail"
|
||||
visible={Boolean(id)}
|
||||
width={800}
|
||||
visible={Boolean(id) && !suspended}
|
||||
width={Math.min(800, window.innerWidth - chatOffset)}
|
||||
style={{ right: chatOffset }}
|
||||
maskStyle={{ right: chatOffset }}
|
||||
title={
|
||||
<span>
|
||||
Alpha 详情 <code className="muted">{id}</code>
|
||||
@@ -147,6 +170,30 @@ export function AlphaDetail({
|
||||
<Spin />
|
||||
) : (
|
||||
<>
|
||||
{conflict && (
|
||||
<Banner
|
||||
type="warning"
|
||||
description={
|
||||
<span>
|
||||
研究记录已被其他操作更新,你的草稿已保留。请先复制需要保留的内容,再
|
||||
<button
|
||||
className="text-link"
|
||||
onClick={() => {
|
||||
if (detail) {
|
||||
dirty.current = false;
|
||||
setResearch(detail.research);
|
||||
setTagText(detail.research.tags.join(", "));
|
||||
setConflict(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
载入最新记录
|
||||
</button>
|
||||
。
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div className="detail-title">
|
||||
<div>
|
||||
<h2>{detail.name || detail.id}</h2>
|
||||
|
||||
@@ -17,6 +17,7 @@ export function JobPanel({
|
||||
onClose,
|
||||
onChange,
|
||||
onAccount,
|
||||
chatOffset = 0,
|
||||
}: {
|
||||
visible: boolean;
|
||||
jobs: Job[];
|
||||
@@ -24,6 +25,7 @@ export function JobPanel({
|
||||
onClose: () => void;
|
||||
onChange: () => void;
|
||||
onAccount: () => void;
|
||||
chatOffset?: number;
|
||||
}) {
|
||||
const [errors, setErrors] = useState<
|
||||
Record<string, { alpha_id: string; error: string }[]>
|
||||
@@ -46,7 +48,9 @@ export function JobPanel({
|
||||
className="job-panel"
|
||||
title="同步任务"
|
||||
visible={visible}
|
||||
width={520}
|
||||
width={Math.min(520, window.innerWidth - chatOffset)}
|
||||
style={{ right: chatOffset }}
|
||||
maskStyle={{ right: chatOffset }}
|
||||
onCancel={onClose}
|
||||
>
|
||||
<p className="muted">同步进度保存在服务端,关闭此面板不会中断任务。</p>
|
||||
|
||||
Reference in New Issue
Block a user