|
|
@@ -28,9 +28,10 @@ import {
|
|
|
PlayCircleOutlined,
|
|
|
MobileOutlined,
|
|
|
CloudSyncOutlined,
|
|
|
+ FileTextOutlined,
|
|
|
} from "@ant-design/icons";
|
|
|
import type { AiOrderV2Item, AiOrderV2Params, WorkflowTaskMessage } from "@/api/aiOrderV2";
|
|
|
-import { getAiOrderV2List, getAiOrderV2Detail, queryAiOrderV2Result } from "@/api/aiOrderV2";
|
|
|
+import { getAiOrderV2List, getAiOrderV2Detail, queryAiOrderV2Result, getAiOrderV2TaskLog } from "@/api/aiOrderV2";
|
|
|
|
|
|
const { Title } = Typography;
|
|
|
|
|
|
@@ -214,6 +215,11 @@ export function AiOrderV2Page() {
|
|
|
const [queryResultData, setQueryResultData] = useState<WorkflowTaskMessage | null>(null);
|
|
|
const [queryResultTaskId, setQueryResultTaskId] = useState<string>("");
|
|
|
|
|
|
+ const [taskLogOpen, setTaskLogOpen] = useState(false);
|
|
|
+ const [taskLogLoading, setTaskLogLoading] = useState(false);
|
|
|
+ const [taskLogData, setTaskLogData] = useState<string[]>([]);
|
|
|
+ const [taskLogTaskId, setTaskLogTaskId] = useState<string>("");
|
|
|
+
|
|
|
const fetchData = useCallback(async () => {
|
|
|
setLoading(true);
|
|
|
try {
|
|
|
@@ -294,6 +300,27 @@ export function AiOrderV2Page() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ async function handleTaskLog(taskId?: string) {
|
|
|
+ if (!taskId) {
|
|
|
+ message.warning(t("aiOrderV2.taskLogNoTaskId"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setTaskLogOpen(true);
|
|
|
+ setTaskLogTaskId(taskId);
|
|
|
+ setTaskLogData([]);
|
|
|
+ setTaskLogLoading(true);
|
|
|
+ try {
|
|
|
+ const res = await getAiOrderV2TaskLog(taskId);
|
|
|
+ setTaskLogData(res ?? []);
|
|
|
+ message.success(t("aiOrderV2.taskLogSuccess"));
|
|
|
+ } catch {
|
|
|
+ message.error(t("aiOrderV2.taskLogFailed"));
|
|
|
+ setTaskLogData([]);
|
|
|
+ } finally {
|
|
|
+ setTaskLogLoading(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const QUERY_STATUS_MAP: Record<string, { i18nKey: string; color: string }> = {
|
|
|
successes: { i18nKey: "aiOrderV2.queryStatusSuccesses", color: "green" },
|
|
|
failed: { i18nKey: "aiOrderV2.queryStatusFailed", color: "red" },
|
|
|
@@ -605,6 +632,15 @@ export function AiOrderV2Page() {
|
|
|
>
|
|
|
{t("aiOrderV2.queryResult")}
|
|
|
</Button>
|
|
|
+ <Button
|
|
|
+ type="link"
|
|
|
+ size="small"
|
|
|
+ icon={<FileTextOutlined />}
|
|
|
+ onClick={() => handleTaskLog(r.taskId)}
|
|
|
+ disabled={!r.taskId}
|
|
|
+ >
|
|
|
+ {t("aiOrderV2.taskLog")}
|
|
|
+ </Button>
|
|
|
</div>
|
|
|
),
|
|
|
},
|
|
|
@@ -970,6 +1006,43 @@ export function AiOrderV2Page() {
|
|
|
<span className="text-gray-300">—</span>
|
|
|
)}
|
|
|
</Modal>
|
|
|
+
|
|
|
+ <Modal
|
|
|
+ title={t("aiOrderV2.taskLogTitle", { taskId: taskLogTaskId })}
|
|
|
+ open={taskLogOpen}
|
|
|
+ onCancel={() => setTaskLogOpen(false)}
|
|
|
+ footer={null}
|
|
|
+ width={800}
|
|
|
+ >
|
|
|
+ {taskLogLoading ? (
|
|
|
+ <div className="py-8 text-center text-gray-500">
|
|
|
+ {t("aiOrderV2.taskLogLoading")}
|
|
|
+ </div>
|
|
|
+ ) : taskLogData.length > 0 ? (
|
|
|
+ <div>
|
|
|
+ <div className="mb-2 text-xs text-gray-400">
|
|
|
+ {t("aiOrderV2.taskLogLines", { count: taskLogData.length })}
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ className="rounded-lg border border-gray-200 bg-gray-950 p-4 overflow-auto"
|
|
|
+ style={{ maxHeight: 480 }}
|
|
|
+ >
|
|
|
+ <pre className="m-0 text-xs leading-5 text-green-400 whitespace-pre-wrap font-mono">
|
|
|
+ {taskLogData.map((line, idx) => (
|
|
|
+ <div key={idx} className="hover:bg-gray-800/50 px-1 -mx-1 rounded">
|
|
|
+ <span className="select-none text-gray-600 mr-3">{String(idx + 1).padStart(3, " ")}</span>
|
|
|
+ {line}
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </pre>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ) : (
|
|
|
+ <div className="py-8 text-center text-gray-400">
|
|
|
+ {t("aiOrderV2.taskLogEmpty")}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </Modal>
|
|
|
</div>
|
|
|
);
|
|
|
}
|